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

import { CalendarIcon, PlusCircleIcon } from 'lucide-react'
import { MeiliSearchFilterBuilder } from 'meilisearch-helper'
import { Suspense, useState } from 'react'
import { Await, Outlet, 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 { Kbd } from '@repo/ui/components/ui/kbd'
import { ExportMenu } from '@repo/ui/components/export-menu'
import { createSearch } from '@repo/util/meili'
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({ context, request }: Route.LoaderArgs) {
  const { searchParams } = new URL(request.url)
  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()

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

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

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

const formatted = new Intl.DateTimeFormat('en-CA', {
  year: 'numeric',
  month: '2-digit',
  day: '2-digit'
})

export default function Route({ loaderData: { data } }: Route.ComponentProps) {
  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">Matrículas</h1>
      </div>

      <Await resolve={data}>
        {({ hits, page, hitsPerPage, totalHits }) => (
          <DataTable
            sort={[{ id: 'created_at', desc: true }]}
            columns={columns}
            data={hits as Enrollment[]}
            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 gap-2.5 mb-2.5">
              {selectedRows.length ? (
                <>
                  <div className="flex gap-2.5 items-center">
                    <ExportMenu
                      name="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) => {
                          setSearchParams((searchParams) => {
                            if (!props) {
                              searchParams.delete('from')
                              searchParams.delete('to')
                              return searchParams
                            }

                            const { rangeField, dateRange } = props

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

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

                    <div className="lg:ml-auto flex gap-2.5">
                      <DataTableViewOptions />
                    </div>
                  </div>
                </>
              )}
            </div>
          </DataTable>
        )}
      </Await>

      <Outlet />
    </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: new Date(from_),
      to: new Date(to)
    }
  }
}
