"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,
  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 { Button } from "@/components/ui/button";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { TableCell } from "@/components/ui/table";

import { createBannerColumns } from "./columns";
import { BANNER_SITE_OPTIONS, bannerCategoryFilterOptions } from "./constants";
import {
  BANNER_STATUS_FILTER_OPTIONS,
  type BannerFilters,
  type BannerRow,
} from "./schema";
import { exportBannersCsv } from "./export-csv";
import type { FormSelectOption } from "@/app/dashboard/_components/form";

const PRIORITY_SAVE_HREF = "/dashboard/master/banners/priority";

type Props = {
  data: BannerRow[];
  initialFilters: BannerFilters;
  categoryOptions: FormSelectOption[];
  pagination: ServerPaginationMeta;
};

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

export function BannersTable({
  data,
  initialFilters,
  categoryOptions,
  pagination: serverPagination,
}: Props) {
  const router = useRouter();
  const { filters, setFilter } = useMasterListFilters(initialFilters, [
    "categoryId",
    "status",
    "site",
  ] as const);
  const prioritiesRef = React.useRef<Record<number, string>>(buildPriorityMap(data));
  const { pagination, onPaginationChange, totalCount } = useServerPagination(serverPagination);
  const categoryFilterOptions = React.useMemo(
    () => bannerCategoryFilterOptions(categoryOptions),
    [categoryOptions],
  );

  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(
    () => createBannerColumns({ 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 updateFilter = <K extends keyof BannerFilters>(
    key: K,
    value: BannerFilters[K],
  ) => {
    setFilter(key, value);
  };

  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(value) || 0,
            ]),
          ),
        },
        fallbackError: "Banner priority could not be updated.",
      });
      toast.success(response.message ?? "Priority successfully updated!");
      router.refresh();
    } catch (error) {
      toast.error(error instanceof Error ? error.message : "Banner priority could not be updated.");
    }
  };

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

      <DataTableShell
        table={table}
        columnCount={columns.length}
        emptyMessage="No banners match your filters."
        renderFilterCell={(header) =>
          renderFilterCell(header, filters, updateFilter, categoryFilterOptions)
        }
      />

      <DataTablePagination
        table={table}
        totalRows={totalCount}
        itemNoun="banner"
        idPrefix="banners"
      />

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

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

  if (columnId === "categoryName") {
    return (
      <TableCell key={header.id} className="p-2">
        <Select
          value={filters.categoryId}
          onValueChange={(value) => updateFilter("categoryId", value)}
        >
          <SelectTrigger className="h-8 bg-background text-xs">
            <SelectValue placeholder="Category" />
          </SelectTrigger>
          <SelectContent>
            {categoryFilterOptions.map((option) => (
              <SelectItem key={option.value} value={option.value}>
                {option.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </TableCell>
    );
  }

  if (columnId === "status") {
    return (
      <TableCell key={header.id} className="p-2">
        <Select
          value={filters.status}
          onValueChange={(value) =>
            updateFilter("status", value as BannerFilters["status"])
          }
        >
          <SelectTrigger className="h-8 bg-background text-xs">
            <SelectValue placeholder="Status" />
          </SelectTrigger>
          <SelectContent>
            {BANNER_STATUS_FILTER_OPTIONS.map((option) => (
              <SelectItem key={option.value} value={option.value}>
                {option.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </TableCell>
    );
  }

  if (columnId === "siteLabel") {
    return (
      <TableCell key={header.id} className="p-2">
        <Select
          value={filters.site}
          onValueChange={(value) => updateFilter("site", value as BannerFilters["site"])}
        >
          <SelectTrigger className="h-8 bg-background text-xs">
            <SelectValue placeholder="Site" />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="all">All sites</SelectItem>
            {BANNER_SITE_OPTIONS.map((option) => (
              <SelectItem key={option.value} value={option.value}>
                {option.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </TableCell>
    );
  }

  return null;
}
