"use client"

import { isApiSuccess } from "@/lib/api-messages";
import { toastApiError } from "@/lib/toast-api-error";
import { formatPlainAmount } from "@/lib/format/numbers";
import * as React from "react"
import { useRouter } from "next/navigation"
import {
  flexRender,
  getCoreRowModel,
  useReactTable,
  type PaginationState,
} from "@tanstack/react-table"
import { toast } from "sonner"

import {
  DataTablePagination,
  useDebouncedValue,
} from "@/app/dashboard/_components/data-table"
import { Input } from "@/components/ui/input"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"
import { SETTINGS_INPUT_CLASS } from "@/components/settings/constants"
import { requestDashboardApi } from "@/lib/dashboard-api-client"
import { cn } from "@/lib/utils"

import {
  buildUnderlyingAliasHref,
  DEFAULT_PAGE_SIZE,
} from "./constants"
import { createUnderlyingAliasColumns } from "./columns"
import type { UnderlyingAliasRow } from "./schema"

const DELETE_HREF = "/dashboard/master-table/underlying-alias/delete"

type Props = {
  data: UnderlyingAliasRow[]
  filters: {
    aliasCode: string
    aliasIsin: string
    aliasSource: string
  }
  totalCount: number
  page: number
  pageSize: number
  pageCount: number
}

export function UnderlyingAliasTable({
  data,
  filters,
  totalCount,
  page,
  pageSize,
  pageCount,
}: Props) {
  const router = useRouter()
  const [aliasCodeDraft, setAliasCodeDraft] = React.useState(filters.aliasCode)
  const [aliasIsinDraft, setAliasIsinDraft] = React.useState(filters.aliasIsin)
  const [aliasSourceDraft, setAliasSourceDraft] = React.useState(filters.aliasSource)
  const debouncedAliasCode = useDebouncedValue(aliasCodeDraft)
  const debouncedAliasIsin = useDebouncedValue(aliasIsinDraft)
  const debouncedAliasSource = useDebouncedValue(aliasSourceDraft)

  const navigate = React.useCallback(
    (
      next: {
        aliasCode?: string
        aliasIsin?: string
        aliasSource?: string
        page?: number
        pageSize?: number
      },
      options?: { replace?: boolean },
    ) => {
      const href = buildUnderlyingAliasHref({
        aliasCode: next.aliasCode ?? filters.aliasCode,
        aliasIsin: next.aliasIsin ?? filters.aliasIsin,
        aliasSource: next.aliasSource ?? filters.aliasSource,
        page: next.page ?? page,
        pageSize: next.pageSize ?? pageSize,
      })

      if (options?.replace) {
        router.replace(href, { scroll: false })
        return
      }

      router.push(href, { scroll: false })
    },
    [
      filters.aliasCode,
      filters.aliasIsin,
      filters.aliasSource,
      page,
      pageSize,
      router,
    ],
  )

  React.useEffect(() => {
    setAliasCodeDraft(filters.aliasCode)
  }, [filters.aliasCode])

  React.useEffect(() => {
    setAliasIsinDraft(filters.aliasIsin)
  }, [filters.aliasIsin])

  React.useEffect(() => {
    setAliasSourceDraft(filters.aliasSource)
  }, [filters.aliasSource])

  React.useEffect(() => {
    const normalized = debouncedAliasCode.trim()
    if (normalized === filters.aliasCode) return
    navigate({ aliasCode: normalized, page: 1 }, { replace: true })
  }, [debouncedAliasCode, filters.aliasCode, navigate])

  React.useEffect(() => {
    const normalized = debouncedAliasIsin.trim()
    if (normalized === filters.aliasIsin) return
    navigate({ aliasIsin: normalized, page: 1 }, { replace: true })
  }, [debouncedAliasIsin, filters.aliasIsin, navigate])

  React.useEffect(() => {
    const normalized = debouncedAliasSource.trim()
    if (normalized === filters.aliasSource) return
    navigate({ aliasSource: normalized, page: 1 }, { replace: true })
  }, [debouncedAliasSource, filters.aliasSource, navigate])

  const onDelete = React.useCallback(async (aliasCode: string) => {
    try {
      await requestDashboardApi<{ status?: string }>({
        url: DELETE_HREF,
        method: "POST",
        body: { alias_code: aliasCode },
        fallbackError: "Could not delete underlying alias.",
        validate: (payload) => isApiSuccess(payload),
      })
      toast.success("Underlying alias deleted.")
      router.refresh()
    } catch (error) {
      toastApiError(error, "Could not delete underlying alias.")
    }
  }, [router])

  const columns = React.useMemo(
    () => createUnderlyingAliasColumns(onDelete),
    [onDelete],
  )

  const pagination = React.useMemo<PaginationState>(
    () => ({
      pageIndex: Math.max(page - 1, 0),
      pageSize,
    }),
    [page, pageSize],
  )

  const table = useReactTable({
    data,
    columns,
    state: { pagination },
    pageCount,
    manualPagination: true,
    onPaginationChange: (updater) => {
      const next = typeof updater === "function" ? updater(pagination) : updater
      const nextPageSize = next.pageSize > 0 ? next.pageSize : pageSize
      const nextPage = nextPageSize !== pageSize ? 1 : Math.max(next.pageIndex + 1, 1)

      navigate({
        page: nextPage,
        pageSize: nextPageSize,
      })
    },
    getCoreRowModel: getCoreRowModel(),
    getRowId: (row) => row.aliasCode,
  })

  const start = totalCount === 0 ? 0 : (page - 1) * pageSize + 1
  const end = Math.min(page * pageSize, totalCount)
  const headers = table.getHeaderGroups()[0]?.headers ?? []

  return (
    <div className="space-y-4">
      <p className="text-sm text-muted-foreground">
        Displaying {start}–{end} of {formatPlainAmount(totalCount)} results.
      </p>

      <div className="grid gap-2 md:grid-cols-3">
        <Input
          className={cn(SETTINGS_INPUT_CLASS, "h-8")}
          placeholder="Filter alias code"
          value={aliasCodeDraft}
          onChange={(event) => setAliasCodeDraft(event.target.value)}
        />
        <Input
          className={cn(SETTINGS_INPUT_CLASS, "h-8")}
          placeholder="Filter real ISIN"
          value={aliasIsinDraft}
          onChange={(event) => setAliasIsinDraft(event.target.value)}
        />
        <Input
          className={cn(SETTINGS_INPUT_CLASS, "h-8")}
          placeholder="Filter alias source"
          value={aliasSourceDraft}
          onChange={(event) => setAliasSourceDraft(event.target.value)}
        />
      </div>

      <div className="rounded-md border">
        <Table>
          <TableHeader>
            <TableRow>
              {headers.map((header) => (
                <TableHead key={header.id}>
                  {header.isPlaceholder
                    ? null
                    : flexRender(header.column.columnDef.header, header.getContext())}
                </TableHead>
              ))}
            </TableRow>
          </TableHeader>
          <TableBody>
            {table.getRowModel().rows.length ? (
              table.getRowModel().rows.map((row) => (
                <TableRow key={row.id}>
                  {row.getVisibleCells().map((cell) => (
                    <TableCell key={cell.id}>
                      {flexRender(cell.column.columnDef.cell, cell.getContext())}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            ) : (
              <TableRow>
                <TableCell colSpan={columns.length} className="h-24 text-center text-muted-foreground">
                  No underlying aliases found.
                </TableCell>
              </TableRow>
            )}
          </TableBody>
        </Table>
      </div>

      <DataTablePagination
        table={table}
        totalRows={totalCount}
        itemNoun="record"
        idPrefix="underlying-alias"
        pageSizes={[10, 20, DEFAULT_PAGE_SIZE, 100]}
      />
    </div>
  )
}
