"use client";

import * as React from "react";

import { getCoreRowModel, useReactTable, type Header } from "@tanstack/react-table";
import { useRouter } from "next/navigation";
import { toast } from "sonner";

import {
  DataTablePagination,
  DataTableShell,
  MasterSelectFilterCell,
  MasterTextFilterCell,
  useServerPagination,
  type ServerPaginationMeta,
} from "@/app/dashboard/_components/data-table";
import { useMasterListFilters } from "@/hooks/use-master-list-filters";
import { requestDashboardApi } from "@/lib/dashboard-api-client";
import { toastApiError } from "@/lib/toast-api-error";
import { Button } from "@/components/ui/button";

import { createCommodityNameColumns } from "./columns";
import {
  COMMODITY_NAME_STATUS_OPTIONS,
  type CommodityNameFilters,
  type CommodityNameRow,
} from "./schema";
import { exportCommodityNameCsv } from "./export-csv";

const PRIORITY_SAVE_HREF = "/dashboard/master/commodity-name/priority";
const PRIORITY_ERROR = "Commodity name priority could not be updated.";

const FILTER_KEYS = ["masterName", "status"] as const;
const TEXT_FILTER_KEYS = ["masterName"] as const;

type Props = {
  data: CommodityNameRow[];
  initialFilters: CommodityNameFilters;
  pagination: ServerPaginationMeta;
};

function buildPriorityMap(rows: CommodityNameRow[]) {
  return Object.fromEntries(rows.map((row) => [row.id, String(row.priority)]));
}

export function CommodityNamesTable({
  data,
  initialFilters,
  pagination: serverPagination,
}: Props) {
  const router = useRouter();
  const { filters, setFilter, drafts, setDraft } = useMasterListFilters(
    initialFilters,
    FILTER_KEYS,
    TEXT_FILTER_KEYS,
  );
  const { pagination, onPaginationChange, totalCount } = useServerPagination(serverPagination);

  // Priorities live in a ref rather than state (and as strings): the inputs are
  // uncontrolled here so typing a priority does not re-render the whole grid.
  // That is why this table does not use the shared `usePrioritySave`.
  const prioritiesRef = React.useRef<Record<number, string>>(buildPriorityMap(data));

  React.useEffect(() => {
    prioritiesRef.current = buildPriorityMap(data);
  }, [data]);

  const onPriorityChange = React.useCallback((id: number, priority: string) => {
    prioritiesRef.current = { ...prioritiesRef.current, [id]: priority };
  }, []);

  const columns = React.useMemo(
    () => createCommodityNameColumns({ onPriorityChange }),
    [onPriorityChange],
  );

  const table = useReactTable({
    data,
    columns,
    state: { pagination },
    onPaginationChange,
    manualPagination: true,
    pageCount: serverPagination.pageCount,
    rowCount: totalCount,
    getCoreRowModel: getCoreRowModel(),
    getRowId: (row) => String(row.id),
  });

  const handlePrioritySave = async () => {
    try {
      const response = await requestDashboardApi<{ message?: string }>({
        url: PRIORITY_SAVE_HREF,
        method: "POST",
        body: {
          priority: Object.fromEntries(
            Object.entries(prioritiesRef.current).map(([id, value]) => [
              id,
              Number.parseInt(value || "0", 10) || 0,
            ]),
          ),
        },
        fallbackError: PRIORITY_ERROR,
      });
      toast.success(response.message ?? "Priority successfully updated!");
      router.refresh();
    } catch (error) {
      toastApiError(error, PRIORITY_ERROR);
    }
  };

  const renderFilterCell = (header: Header<CommodityNameRow, unknown>) => {
    switch (header.column.id) {
      case "masterName":
        return (
          <MasterTextFilterCell
            cellKey={header.id}
            value={drafts.masterName}
            placeholder="Commodity name"
            onChange={(value) => setDraft("masterName", value)}
          />
        );
      case "status":
        return (
          <MasterSelectFilterCell
            cellKey={header.id}
            value={filters.status}
            placeholder="Status"
            options={COMMODITY_NAME_STATUS_OPTIONS}
            onChange={(value) => setFilter("status", value)}
          />
        );
      default:
        return null;
    }
  };

  return (
    <div className="space-y-4">
      <div className="flex justify-end">
        <Button
          type="button"
          variant="secondary"
          size="sm"
          onClick={() => exportCommodityNameCsv(data)}
        >
          Export filtered
        </Button>
      </div>

      <DataTableShell
        table={table}
        columnCount={columns.length}
        emptyMessage="No commodity names match your filters."
        renderFilterCell={renderFilterCell}
      />

      <DataTablePagination
        table={table}
        totalRows={totalCount}
        itemNoun="commodity name"
        idPrefix="commodity-names"
      />

      <div className="flex justify-end border-t pt-4">
        <Button type="button" onClick={handlePrioritySave}>
          Update priority
        </Button>
      </div>
    </div>
  );
}
