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

import { useToggle } from 'ahooks'
import {
  CalendarIcon,
  SearchIcon,
  CopyIcon,
  CopyPlusIcon,
  Trash2Icon,
  PlusIcon,
  XIcon,
  ChevronsUpDownIcon,
  CheckIcon
} from 'lucide-react'
import { Link } from 'react-router'
import { Controller, useFieldArray, useForm } from 'react-hook-form'
import { Fragment, use, useMemo, useState } from 'react'
import { format } from 'date-fns'
import { ptBR } from 'react-day-picker/locale'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'

import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList
} from '@repo/ui/components/ui/command'
import {
  Breadcrumb,
  BreadcrumbItem,
  BreadcrumbLink,
  BreadcrumbList,
  BreadcrumbPage,
  BreadcrumbSeparator
} from '@repo/ui/components/ui/breadcrumb'
import {
  InputGroup,
  InputGroupAddon,
  InputGroupInput,
  InputGroupText
} from '@repo/ui/components/ui/input-group'
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle
} from '@repo/ui/components/ui/card'
import { Spinner } from '@repo/ui/components/ui/spinner'
import { Input } from '@repo/ui/components/ui/input'
import { Button } from '@repo/ui/components/ui/button'
import { Separator } from '@repo/ui/components/ui/separator'
import {
  Popover,
  PopoverContent,
  PopoverTrigger
} from '@repo/ui/components/ui/popover'
import { Label } from '@repo/ui/components/ui/label'
import { Calendar } from '@repo/ui/components/ui/calendar'
import { createSearch } from '@repo/util/meili'
import { Await } from 'react-router'
import { cn } from '@repo/ui/lib/utils'
import Fuse from 'fuse.js'
import { useIsMobile } from '@repo/ui/hooks/use-mobile'

const enrollment = z.object({
  user: z
    .object({
      id: z.string(),
      name: z.string(),
      email: z.string(),
      cpf: z.string()
    })
    .required(),
  course: z
    .object({
      id: z.string(),
      name: z.string(),
      access_period: z.number(),
      unit_price: z.number()
    })
    .required(),
  deduplication_window: z
    .object({
      offset_days: z.number()
    })
    .optional(),
  scheduled_for: z.date().optional().nullable()
})

const formSchema = z.object({
  enrollments: z.array(enrollment).min(1).max(100)
})

type Schema = z.infer<typeof formSchema>

const MAX_ITEMS = 100

export function meta({}: Route.MetaArgs) {
  return [{ title: 'Adicionar matrícula' }]
}

export async function loader({ context }: Route.LoaderArgs) {
  const courses = createSearch({
    index: 'saladeaula_courses',
    sort: ['created_at:desc'],
    filter: 'unlisted NOT EXISTS',
    hitsPerPage: 100,
    env: context.cloudflare.env
  })

  return { courses }
}

export async function action({}: Route.ActionArgs) {
  return {}
}

export default function Route({
  loaderData: { courses }
}: Route.ComponentProps) {
  const form = useForm({
    resolver: zodResolver(formSchema),
    defaultValues: {
      enrollments: [{ user: undefined, course: undefined, scheduled_for: null }]
    }
  })
  const { formState, control, handleSubmit, getValues } = form
  const { fields, insert, remove, append } = useFieldArray({
    control,
    name: 'enrollments'
  })

  const onSubmit = async (data: Schema) => {
    console.log(data)
  }

  const duplicateRow = (index: number, times: number = 1) => {
    if (fields.length + times > MAX_ITEMS) {
      return
    }

    const values = getValues(`enrollments.${index}`)
    Array.from({ length: times }, (_, i) => {
      insert(index + 1 + i, values)
    })
  }

  return (
    <div className="space-y-2.5">
      <Breadcrumb>
        <BreadcrumbList>
          <BreadcrumbItem>
            <BreadcrumbLink asChild>
              <Link to="../enrollments">Matrículas</Link>
            </BreadcrumbLink>
          </BreadcrumbItem>
          <BreadcrumbSeparator />
          <BreadcrumbItem>
            <BreadcrumbPage>Adicionar matrícula</BreadcrumbPage>
          </BreadcrumbItem>
        </BreadcrumbList>
      </Breadcrumb>

      <form
        onSubmit={handleSubmit(onSubmit)}
        className="lg:max-w-4xl mx-auto space-y-2.5"
        autoComplete="off"
        data-1p-ignore="true"
        data-lpignore="true"
      >
        <Card>
          <CardHeader>
            <CardTitle className="text-2xl">Adicionar matrícula</CardTitle>
            <CardDescription>
              Siga os passos abaixo para adicionar uma nova matrícula
            </CardDescription>
          </CardHeader>

          <CardContent className="space-y-4">
            <div className="grid lg:grid-cols-[repeat(3,1fr)_auto] w-full gap-1.5">
              {/* Header */}
              <>
                <div className="max-lg:hidden text-foreground font-medium text-sm">
                  Colaborador
                </div>
                <div className="max-lg:hidden text-foreground font-medium text-sm">
                  Curso
                </div>
                <div className="max-lg:hidden text-foreground font-medium text-sm">
                  Matriculado em
                </div>
                <div></div>
              </>

              {/* Rows */}
              <>
                {fields.map((field, index) => (
                  <Fragment key={field.id}>
                    {index >= 1 && <div className="h-2.5 lg:hidden"></div>}

                    <InputGroup>
                      <InputGroupInput placeholder="Search..." />
                      <InputGroupAddon>
                        <SearchIcon />
                      </InputGroupAddon>
                    </InputGroup>

                    <Controller
                      control={control}
                      name={`enrollments.${index}.course`}
                      render={({ field: { value, onChange } }) => (
                        <FacetedFilter
                          value={value}
                          onChange={onChange}
                          options={courses}
                        />
                      )}
                    />

                    <Controller
                      control={control}
                      name={`enrollments.${index}.scheduled_for`}
                      render={({ field: { value, onChange } }) => (
                        <ScheduledForInput value={value} onChange={onChange} />
                      )}
                    />

                    {/* Action */}
                    <div className="flex gap-1.5">
                      <Button
                        type="button"
                        tabIndex={-1}
                        variant="outline"
                        className="cursor-pointer"
                        onClick={() => duplicateRow(index)}
                        title="Duplicar linha"
                      >
                        <CopyIcon />
                      </Button>

                      <DuplicateRowMultipleTimes
                        index={index}
                        duplicateRow={duplicateRow}
                      />

                      <Button
                        tabIndex={-1}
                        variant="destructive"
                        className="cursor-pointer"
                        disabled={fields.length == 1}
                        onClick={() => remove(index)}
                      >
                        <Trash2Icon />
                      </Button>
                    </div>
                  </Fragment>
                ))}
              </>
            </div>

            <Button
              type="button"
              onClick={() =>
                append({
                  user: undefined,
                  course: undefined,
                  scheduled_for: null
                })
              }
              className="cursor-pointer"
              disabled={fields.length == MAX_ITEMS}
              variant="outline"
              size="sm"
            >
              <PlusIcon /> Adicionar
            </Button>

            <Separator />

            <Button
              type="submit"
              className="cursor-pointer"
              disabled={formState.isSubmitting}
            >
              {formState.isSubmitting && <Spinner />}
              Continuar
            </Button>
          </CardContent>
        </Card>
      </form>
    </div>
  )
}

type Course = {
  id: string
  name: string
  access_period: number
  metadata__unit_price?: number
}

interface FacetedFilterProps {
  value?: Course
  options: Promise<{ hits: any[] }>
  onChange?: (value: any) => void
}

function FacetedFilter({ value, onChange, options }: FacetedFilterProps) {
  const [search, setSearch] = useState('')
  const [open, { set }] = useToggle()
  const { hits } = use(options)
  const fuse = useMemo(() => {
    return new Fuse(hits, {
      keys: ['name'],
      threshold: 0.3,
      includeMatches: true
    })
  }, [hits])

  const filtered = useMemo(() => {
    if (!search) {
      return hits
    }

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

  return (
    <Popover open={open} onOpenChange={set}>
      <PopoverTrigger asChild>
        <InputGroup>
          <InputGroupInput readOnly value={value?.name || ''} />
          <InputGroupAddon align="inline-end">
            <ChevronsUpDownIcon />
          </InputGroupAddon>
        </InputGroup>
      </PopoverTrigger>

      <PopoverContent className="w-72 p-0" align="start">
        <Command shouldFilter={false}>
          <CommandInput
            placeholder="Curso"
            autoComplete="off"
            onValueChange={setSearch}
          />
          <CommandList>
            <CommandEmpty>Nenhum resultado encontrado.</CommandEmpty>
            <CommandGroup>
              {filtered
                .filter(
                  ({ metadata__unit_price = 0 }) => metadata__unit_price > 0
                )
                .map(
                  ({
                    id,
                    name,
                    access_period,
                    metadata__unit_price: unit_price
                  }) => (
                    <CommandItem
                      key={id}
                      value={id}
                      className="cursor-pointer"
                      onSelect={() => {
                        onChange?.({
                          id,
                          name,
                          access_period: Number(access_period),
                          unit_price: Number(unit_price)
                        })
                        set(false)
                      }}
                    >
                      {name}
                      <CheckIcon
                        className={cn(
                          'ml-auto',
                          value?.id === id ? 'opacity-100' : 'opacity-0'
                        )}
                      />
                    </CommandItem>
                  )
                )}
            </CommandGroup>
          </CommandList>
        </Command>
      </PopoverContent>
    </Popover>
  )
}

function ScheduledForInput({ value, onChange }) {
  const today = new Date()
  const [open, { set }] = useToggle()
  const [selected, setDate] = useState<Date | undefined>(value)
  const displayValue = !selected
    ? 'Imediatamente'
    : format(selected, 'dd/MM/yyyy')

  return (
    <Popover open={open} onOpenChange={set}>
      <PopoverTrigger asChild>
        <InputGroup>
          <InputGroupInput readOnly type="search" value={displayValue} />
          <InputGroupAddon>
            <CalendarIcon />
          </InputGroupAddon>
          {selected && (
            <InputGroupAddon align="inline-end" className="mr-0">
              <Button
                variant="link"
                size="icon-sm"
                className="cursor-pointer text-black dark:text-white"
                onClick={(e) => {
                  e.preventDefault()
                  setDate(undefined)
                  onChange?.(undefined)
                  set(false)
                }}
              >
                <XIcon />
              </Button>
            </InputGroupAddon>
          )}
        </InputGroup>
      </PopoverTrigger>
      <PopoverContent className="w-full p-0" align="start">
        <Calendar
          mode="single"
          selected={selected}
          onSelect={(date: Date) => {
            setDate(date)
            onChange?.(date)
            set(false)
          }}
          disabled={{ before: today }}
          startMonth={new Date(today.getFullYear(), 0)}
          endMonth={new Date(today.getFullYear() + 3, 11)}
          captionLayout="dropdown"
          locale={ptBR}
        />
      </PopoverContent>
    </Popover>
  )
}

function DuplicateRowMultipleTimes({
  index,
  duplicateRow
}: {
  index: number
  duplicateRow: (index: number, times: number) => void
}) {
  const [open, { toggle, set }] = useToggle()
  const isMobile = useIsMobile()

  return (
    <Popover open={open} onOpenChange={toggle}>
      <PopoverTrigger asChild>
        <Button
          tabIndex={-1}
          variant="outline"
          className="cursor-pointer"
          title="Duplicar várias vezes"
        >
          <CopyPlusIcon />
        </Button>
      </PopoverTrigger>

      <PopoverContent align={isMobile ? 'start' : 'end'} className="w-80">
        <form
          onSubmit={(e) => {
            e.stopPropagation()
            e.preventDefault()
            const formData = new FormData(e.currentTarget)
            const times = parseInt(formData.get('quantity') as string)
            duplicateRow(index, times)
            set(false)
          }}
        >
          <div className="space-y-2.5">
            <h4 className="leading-none font-medium">Duplicar várias vezes</h4>
            <p className="text-muted-foreground text-sm">
              Duplique o curso desta linha na quantidade desejada para agilizar
              o preenchimento.
            </p>

            <div className="grid grid-cols-3 items-center gap-4">
              <Label htmlFor="quantity">Quantidade</Label>
              <Input
                id="quantity"
                name="quantity"
                type="number"
                defaultValue="2"
                min="2"
                max="100"
                className="col-span-2"
              />
            </div>

            <div className="flex justify-end gap-2.5">
              <Button
                type="button"
                variant="link"
                tabIndex={-1}
                className="cursor-pointer dark:text-white text-black"
                onClick={() => set(false)}
              >
                Cancelar
              </Button>
              <Button type="submit" className="cursor-pointer">
                Duplicar
              </Button>
            </div>
          </div>
        </form>
      </PopoverContent>
    </Popover>
  )
}
