"use client";

import * as React from "react";
import { toast } from "sonner";

import {
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  useReactTable,
  type Header,
  type PaginationState,
} from "@tanstack/react-table";

import {
  DataTableHeaderActions,
  DataTablePagination,
  DataTableShell,
  downloadCsv,
} from "@/app/dashboard/_components/data-table";
import { filterTaxRowsClient } from "@/app/dashboard/plans-orders/_lib/client-column-filters";
import { ErrorBanner } from "@/components/shared/error-banner";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { TableCell } from "@/components/ui/table";

import type { TaxesResult } from "../_lib/taxes-server-api";
import { fetchTaxes } from "./api/taxes.api";
import { createTaxColumns } from "./columns";
import {
  emptyTaxClientFilters,
  type TaxClientFilters,
  type TaxRow,
} from "./schema";

function exportTaxes(rows: TaxRow[]) {
  downloadCsv({
    filename: "taxes",
    headers: ["Name", "Percent", "Is global", "Status", "Date added"],
    rows,
    toRow: (row) => [
      row.name,
      row.percentFormatted,
      row.isGlobalLabel,
      row.statusLabel,
      row.dateAddedIso,
    ],
  });
}

type TaxesTableProps = {
  initialData: TaxesResult;
  initialErrorMessage?: string | null;
};

export function TaxesTable({
  initialData,
  initialErrorMessage = null,
}: TaxesTableProps) {
  const [data, setData] = React.useState(initialData);
  const [errorMessage, setErrorMessage] = React.useState(initialErrorMessage);
  const [isRefreshing, setIsRefreshing] = React.useState(false);
  const [clientFilters, setClientFilters] = React.useState<TaxClientFilters>(emptyTaxClientFilters);
  const [toolbarGlobal, setToolbarGlobal] = React.useState("all");
  const [toolbarStatus, setToolbarStatus] = React.useState("all");
  const [pagination, setPagination] = React.useState<PaginationState>({
    pageIndex: 0,
    pageSize: 20,
  });

  const globalOptions = React.useMemo(
    () => [
      { value: "all", label: "All" },
      ...Object.entries(data.filterOptions.yesNoOptions).map(([value, label]) => ({ value, label })),
    ],
    [data.filterOptions.yesNoOptions],
  );

  const statusOptions = React.useMemo(
    () => [
      { value: "all", label: "All statuses" },
      ...Object.entries(data.filterOptions.statuses).map(([value, label]) => ({ value, label })),
    ],
    [data.filterOptions.statuses],
  );

  const loadTaxes = React.useCallback(
    async (nextFilters: typeof initialData.filters, showToast = false) => {
      setIsRefreshing(true);
      try {
        const result = await fetchTaxes(nextFilters);
        setData(result);
        setErrorMessage(null);
        setPagination((prev) => ({ ...prev, pageIndex: 0 }));
        if (showToast) toast.success("Taxes refreshed");
      } catch (error) {
        const message = error instanceof Error ? error.message : "Failed to load taxes";
        setErrorMessage(message);
        toast.error(message);
      } finally {
        setIsRefreshing(false);
      }
    },
    [],
  );

  const applyToolbarSearch = () => {
    const nextFilters = {
      status: toolbarStatus === "all" ? "" : toolbarStatus,
      is_global: toolbarGlobal === "all" ? "" : toolbarGlobal,
    };

    void loadTaxes(nextFilters, true);
  };

  const filteredData = React.useMemo(
    () => filterTaxRowsClient(data.items, clientFilters),
    [data.items, clientFilters],
  );

  const columns = React.useMemo(
    () => createTaxColumns({ onDeleted: () => void loadTaxes(data.filters) }),
    [data.filters, loadTaxes],
  );

  const table = useReactTable({
    data: filteredData,
    columns,
    state: { pagination },
    onPaginationChange: setPagination,
    getCoreRowModel: getCoreRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getRowId: (row) => String(row.id),
  });

  const updateClientFilter = <K extends keyof TaxClientFilters>(
    key: K,
    value: TaxClientFilters[K],
  ) => {
    setClientFilters((prev) => ({ ...prev, [key]: value }));
    setPagination((prev) => ({ ...prev, pageIndex: 0 }));
  };

  return (
    <div className="space-y-4">
      <ErrorBanner message={errorMessage} />

      <div className="flex flex-col gap-3 lg:flex-row lg:items-end lg:justify-between">
        <div className="flex flex-wrap items-end gap-2">
          <div className="space-y-1">
            <Label htmlFor="taxes-toolbar-global" className="text-xs">
              Is global
            </Label>
            <Select value={toolbarGlobal} onValueChange={setToolbarGlobal}>
              <SelectTrigger id="taxes-toolbar-global" className="h-9 w-[160px]">
                <SelectValue placeholder="Global" />
              </SelectTrigger>
              <SelectContent>
                <SelectGroup>
                  {globalOptions.map((option) => (
                    <SelectItem key={option.value} value={option.value}>
                      {option.label}
                    </SelectItem>
                  ))}
                </SelectGroup>
              </SelectContent>
            </Select>
          </div>
          <div className="space-y-1">
            <Label htmlFor="taxes-toolbar-status" className="text-xs">
              Status
            </Label>
            <Select value={toolbarStatus} onValueChange={setToolbarStatus}>
              <SelectTrigger id="taxes-toolbar-status" className="h-9 w-[180px]">
                <SelectValue placeholder="Status" />
              </SelectTrigger>
              <SelectContent>
                <SelectGroup>
                  {statusOptions.map((option) => (
                    <SelectItem key={option.value} value={option.value}>
                      {option.label}
                    </SelectItem>
                  ))}
                </SelectGroup>
              </SelectContent>
            </Select>
          </div>
          <Button type="button" className="h-9" onClick={applyToolbarSearch} disabled={isRefreshing}>
            Search
          </Button>
        </div>
      </div>

      <DataTableShell
        table={table}
        columnCount={columns.length}
        emptyMessage="No taxes match your filters."
        renderFilterCell={(header) => renderFilterCell(header, clientFilters, updateClientFilter)}
      />

      <DataTablePagination
        table={table}
        totalRows={filteredData.length}
        itemNoun="tax"
        idPrefix="taxes"
      />
    </div>
  );
}

function renderFilterCell(
  header: Header<TaxRow, unknown>,
  filters: TaxClientFilters,
  updateFilter: <K extends keyof TaxClientFilters>(key: K, value: TaxClientFilters[K]) => void,
) {
  const columnId = header.column.id;

  if (columnId === "name") {
    return (
      <TableCell key={header.id} className="p-2">
        <Input
          value={filters.name}
          onChange={(event) => updateFilter("name", event.target.value)}
          placeholder="Tax name"
          className="h-8 bg-background text-xs"
        />
      </TableCell>
    );
  }

  if (columnId === "percent") {
    return (
      <TableCell key={header.id} className="p-2">
        <Input
          value={filters.percent}
          onChange={(event) => updateFilter("percent", event.target.value)}
          placeholder="Percent"
          className="h-8 bg-background text-xs"
        />
      </TableCell>
    );
  }

  return null;
}

export function TaxesHeaderActions({ data }: { data: TaxRow[] }) {
  return (
    <DataTableHeaderActions
      createHref="/dashboard/plans-orders/taxes/create"
      createLabel="Create new"
      onExport={() => exportTaxes(data)}
    />
  );
}
