import type { Route } from './+types'

import Fuse from 'fuse.js'
import {
  BanIcon,
  CircleCheckIcon,
  CircleIcon,
  CircleOffIcon,
  CirclePlusIcon,
  CircleXIcon,
  EllipsisIcon,
  FileBadgeIcon,
  TimerIcon,
  type LucideIcon
} from 'lucide-react'
import { MeiliSearchFilterBuilder } from 'meilisearch-helper'
import { Suspense, useMemo } from 'react'
import { Await, NavLink, useSearchParams } from 'react-router'

import type { User } from '@repo/auth/auth'
import { userContext } from '@repo/auth/context'
import { FacetedFilter } from '@repo/ui/components/faceted-filter'
import { SearchForm } from '@repo/ui/components/search-form'
import { Skeleton } from '@repo/ui/components/skeleton'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger
} from '@repo/ui/components/ui/dropdown-menu'
import {
  Empty,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle
} from '@repo/ui/components/ui/empty'
import {
  Card,
  CardContent,
  CardFooter,
  CardHeader,
  CardTitle,
  CardAction
} from '@repo/ui/components/ui/card'
import { Kbd } from '@repo/ui/components/ui/kbd'
import { Progress } from '@repo/ui/components/ui/progress'
import { createSearch } from '@repo/util/meili'

import placeholder from '@/assets/placeholder.webp'
import { Container } from '@/components/container'
import { Button } from '@repo/ui/components/ui/button'

type Course = {
  name: string
  scormset?: string
}

export type Enrollment = {
  id: string
  course: Course
  status: number
  progress: number
}

export function meta({}: Route.MetaArgs) {
  return [{ title: 'Meus cursos' }]
}

export async function loader({ request, context }: Route.ActionArgs) {
  const user = context.get(userContext) as User
  const { searchParams } = new URL(request.url)
  const status = searchParams.getAll('status') || []
  let builder = new MeiliSearchFilterBuilder().where('user.id', '=', user.sub)

  if (status.length) {
    builder = builder.where('status', 'in', status)
  }

  const enrollments = createSearch({
    index: 'betaeducacao-prod-enrollments',
    filter: builder.build(),
    sort: ['created_at:desc'],
    hitsPerPage: 100,
    env: context.cloudflare.env
  })

  return {
    data: enrollments
  }
}

export default function Component({
  loaderData: { data }
}: Route.ComponentProps) {
  const [searchParams, setSearchParams] = useSearchParams()
  const term = searchParams.get('term') as string

  return (
    <Container className="space-y-4">
      <Suspense fallback={<Skeleton />}>
        <div className="space-y-0.5 mb-8">
          <h1 className="text-2xl font-bold tracking-tight">Meus cursos</h1>
          <p className="text-muted-foreground">
            Aqui você encontra todos os cursos em que está matriculado,
            organizados em um só lugar. Acompanhe seu progresso e continue de
            onde parou.
          </p>
        </div>

        <div className="flex gap-2.5">
          <div className="w-full xl:w-1/3">
            <SearchForm
              defaultValue={term || ''}
              placeholder={
                <>
                  Digite <Kbd>/</Kbd> para pesquisar
                </>
              }
              onChange={(value) =>
                setSearchParams((searchParams) => {
                  searchParams.set('term', String(value))
                  return searchParams
                })
              }
            />
          </div>
          <FacetedFilter
            icon={CirclePlusIcon}
            value={searchParams.getAll('status')}
            onChange={(statuses) => {
              setSearchParams((searchParams) => {
                searchParams.delete('status')

                if (statuses.length) {
                  statuses.forEach((s) =>
                    searchParams.has('status', s)
                      ? null
                      : searchParams.append('status', s)
                  )
                }

                return searchParams
              })
            }}
            title="Status"
            options={Object.entries(statuses).map(([key, value]) => ({
              value: key,
              ...value
            }))}
          />
        </div>

        <Await resolve={data}>
          {({ hits = [] }) => <List term={term} hits={hits as Enrollment[]} />}
        </Await>
      </Suspense>
    </Container>
  )
}

function List({ term, hits = [] }: { term: string; hits: Enrollment[] }) {
  const fuse = useMemo(() => {
    return new Fuse(hits, {
      keys: ['course.name'],
      threshold: 0.3,
      includeMatches: true
    })
  }, [hits])

  const hits_ = useMemo(() => {
    if (!term) {
      return hits
    }

    return fuse.search(term).map(({ item }) => item)
  }, [term, fuse, hits])

  if (hits_.length === 0) {
    return (
      <Empty className="border border-dashed">
        <EmptyHeader>
          <EmptyMedia variant="icon">
            <BanIcon />
          </EmptyMedia>
          <EmptyTitle>Nada encontrado</EmptyTitle>
          <EmptyDescription>
            Nenhum resultado para <mark>{term}</mark>.
          </EmptyDescription>
        </EmptyHeader>
      </Empty>
    )
  }

  return (
    <div className="grid lg:grid-cols-4 gap-5">
      {hits_.map((props: Enrollment, idx) => {
        return <Enrollment key={idx} {...props} />
      })}
    </div>
  )
}

function Enrollment({ id, course, progress }: Enrollment) {
  return (
    <NavLink
      to={course?.scormset ? `/player/${id}` : '/konviva'}
      className="hover:scale-105 transition"
    >
      <Card className="overflow-hidden relative h-96">
        <CardHeader className="z-1 relative">
          <CardTitle className="text-xl/6">{course.name}</CardTitle>
          <CardAction>
            <ActionMenu />
          </CardAction>
        </CardHeader>
        <CardFooter className="absolute z-1 bottom-6 w-full flex gap-1.5">
          <Progress value={progress} />
          <span className="text-xs">{progress}%</span>
        </CardFooter>
        <img
          src={placeholder}
          alt={course.name}
          className="absolute bottom-0 opacity-75"
        />
      </Card>
    </NavLink>
  )
}

function ActionMenu() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button variant="ghost" size="icon-sm" className="cursor-pointer">
          <EllipsisIcon />
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent align="end">
        <DropdownMenuItem disabled={true}>
          <FileBadgeIcon /> Baixar certificado
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

const statuses: Record<
  string,
  { icon: LucideIcon; color?: string; label: string }
> = {
  PENDING: {
    icon: CircleIcon,
    label: 'Não iniciado'
  },
  IN_PROGRESS: {
    icon: TimerIcon,
    color: 'text-blue-400 [&_svg]:text-blue-500',
    label: 'Em andamento'
  },
  COMPLETED: {
    icon: CircleCheckIcon,
    color: 'text-green-400 [&_svg]:text-background [&_svg]:fill-green-500',
    label: 'Concluído'
  },
  FAILED: {
    icon: CircleXIcon,
    color: 'text-red-400 [&_svg]:text-red-500',
    label: 'Reprovado'
  },
  CANCELED: {
    icon: CircleOffIcon,
    color: 'text-orange-400 [&_svg]:text-orange-500',
    label: 'Cancelado'
  }
}
