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

import { DateTime } from 'luxon'
import { CalendarIcon, PlusCircleIcon, PlusIcon } from 'lucide-react'
import { MeiliSearchFilterBuilder } from 'meilisearch-helper'
import { Suspense, useState } from 'react'
import { Await, Link, useParams, useSearchParams } from 'react-router'

import { DataTable, DataTableViewOptions } from '@repo/ui/components/data-table'
import { FacetedFilter } from '@repo/ui/components/faceted-filter'
import { RangeCalendarFilter } from '@repo/ui/components/range-calendar-filter'
import { SearchForm } from '@repo/ui/components/search-form'
import { Skeleton } from '@repo/ui/components/skeleton'
import { Button } from '@repo/ui/components/ui/button'
import { ExportMenu } from '@repo/ui/components/export-menu'
import { Kbd } from '@repo/ui/components/ui/kbd'
import { createSearch } from '@repo/util/meili'
import { cloudflareContext } from '@repo/auth/context'
import { headers, sortings, statuses } from '@repo/ui/routes/enrollments/data'

import { columns, type Enrollment } from './columns'

export function meta({}: Route.MetaArgs) {
  return [{ title: 'Matrículas' }]
}

export async function loader({ params, context, request }: Route.LoaderArgs) {
  const cloudflare = context.get(cloudflareContext)
  const { searchParams } = new URL(request.url)
  const { orgid } = params
  const query = searchParams.get('q') || ''
  const from = searchParams.get('from')
  const to = searchParams.get('to')
  const sort = searchParams.get('sort') || 'created_at:desc'
  const status = searchParams.get('status')
  const page = Number(searchParams.get('p')) + 1
  const hitsPerPage = Number(searchParams.get('perPage')) || 25

  let builder = new MeiliSearchFilterBuilder().where('org_id', '=', orgid)

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

  if (from && to) {
    const [field, from_] = from.split(':')
    builder = builder.where(field, 'between', [from_, to])
  }

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

  return {
    data: enrollments
  }
}

export default function Route({ loaderData: { data } }: Route.ComponentProps) {
  const { orgid } = useParams()
  const [searchParams, setSearchParams] = useSearchParams()
  const [selectedRows, setSelectedRows] = useState<Enrollment[]>([])
  const status = searchParams.get('status')
  const rangeParams = useRangeParams()

  return (
    <Suspense fallback={<Skeleton />}>
      <div className="space-y-0.5 mb-8">
        <h1 className="text-2xl font-bold tracking-tight">
          Gerenciar matrículas
        </h1>
        <p className="text-muted-foreground">
          Matricule colaboradores de forma rápida e acompanhe seu progresso.
        </p>
      </div>

      <Await resolve={data}>
        {({ hits, page = 1, hitsPerPage, totalHits }) => (
          <DataTable
            sort={[{ id: 'created_at', desc: true }]}
            columns={columns}
            data={hits as Enrollment[]}
            columnPinning={{ left: ['select'], right: ['action'] }}
            pageIndex={page - 1}
            pageSize={hitsPerPage}
            setSelectedRows={setSelectedRows}
            rowCount={totalHits}
            columnVisibilityInit={{
              created_at: true,
              completed_at: false,
              started_at: false,
              failed_at: false,
              canceled_at: false
            }}
          >
            <div className="flex max-lg:flex-col gap-2.5 mb-2.5">
              {selectedRows.length ? (
                <>
                  <div className="flex gap-2.5 items-center">
                    <ExportMenu
                      name={`${orgid}_enrollments`}
                      headers={headers}
                      selectedRows={selectedRows}
                    />
                  </div>
                </>
              ) : (
                <>
                  <div className="w-full 2xl:w-1/3">
                    <SearchForm
                      defaultValue={searchParams.get('q') || ''}
                      placeholder={
                        <>
                          Digite <Kbd className="border font-mono">/</Kbd> para
                          pesquisar
                        </>
                      }
                      onChange={(value) =>
                        setSearchParams((searchParams) => {
                          searchParams.set('q', String(value))
                          searchParams.delete('p')
                          return searchParams
                        })
                      }
                    />
                  </div>

                  <div className="flex gap-2.5 max-lg:flex-col w-full">
                    <div className="flex gap-2.5 max-lg:flex-col">
                      <FacetedFilter
                        title="Status"
                        icon={PlusCircleIcon}
                        className="lg:flex-1"
                        value={status ? status.split(',') : []}
                        onChange={(statuses) => {
                          setSearchParams((searchParams) => {
                            searchParams.delete('status')
                            searchParams.delete('p')

                            if (statuses.length) {
                              searchParams.set('status', statuses.join(','))
                            }

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

                      <RangeCalendarFilter
                        title="Período"
                        icon={CalendarIcon}
                        value={rangeParams}
                        className="lg:flex-1"
                        options={Object.entries(sortings).map(
                          ([value, label]) => ({
                            value,
                            label
                          })
                        )}
                        onChange={(props) => {
                          const dt = new Intl.DateTimeFormat('en-CA', {
                            year: 'numeric',
                            month: '2-digit',
                            day: '2-digit'
                          })

                          setSearchParams((searchParams) => {
                            if (!props) {
                              searchParams.delete('from')
                              searchParams.delete('to')
                              return searchParams
                            }

                            const { rangeField, dateRange } = props

                            searchParams.set(
                              'from',
                              `${rangeField}:${dt.format(dateRange?.from)}`
                            )
                            searchParams.set('to', dt.format(dateRange?.to))

                            return searchParams
                          })
                        }}
                      />
                    </div>

                    <div className="lg:ml-auto flex gap-2.5">
                      <DataTableViewOptions className="flex-1" />

                      <Button className="flex-1" asChild>
                        <Link to="add">
                          <PlusIcon /> Adicionar
                        </Link>
                      </Button>
                    </div>
                  </div>
                </>
              )}
            </div>
          </DataTable>
        )}
      </Await>
    </Suspense>
  )
}

function useRangeParams() {
  const [searchParams] = useSearchParams()
  const [from, to] = [searchParams.get('from'), searchParams.get('to')]

  if (!from || !to) {
    return {}
  }

  const [rangeField, from_] = from.split(':')
  return {
    rangeField,
    dateRange: {
      from: DateTime.fromISO(from_).toJSDate(),
      to: DateTime.fromISO(to).toJSDate()
    }
  }
}
