"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,
  DATE_COMPARISONS,
  downloadCsv,
} from "@/app/dashboard/_components/data-table";
import { filterPromoRowsClient } 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 { PromoCodesResult } from "../_lib/promo-codes-server-api";
import { fetchPromoCodes } from "./api/promo-codes.api";
import { createPromoColumns } from "./columns";
import {
  emptyPromoClientFilters,
  type DateComparison,
  type PromoClientFilters,
  type PromoCodeRow,
} from "./schema";

function exportPromoCodes(rows: PromoCodeRow[]) {
  downloadCsv({
    filename: "promo-codes",
    headers: [
      "Code",
      "Type",
      "Discount",
      "Total amount",
      "Total usage",
      "Customer usage",
      "Status",
      "Date start",
      "Date end",
    ],
    rows,
    toRow: (row) => [
      row.code,
      row.typeLabel,
      row.discountFormatted,
      row.totalAmount,
      row.totalUsage === 0 ? "Unlimited" : row.totalUsage,
      row.customerUsage === 0 ? "Unlimited" : row.customerUsage,
      row.statusLabel,
      row.dateStartIso,
      row.dateEndIso,
    ],
  });
}

export function PromoCodesTable({
  initialData,
  initialErrorMessage = null,
}: {
  initialData: PromoCodesResult;
  initialErrorMessage?: string | null;
}) {
  const [data, setData] = React.useState(initialData);
  const [errorMessage, setErrorMessage] = React.useState(initialErrorMessage);
  const [isRefreshing, setIsRefreshing] = React.useState(false);
  const [clientFilters, setClientFilters] =
    React.useState<PromoClientFilters>(emptyPromoClientFilters);
  const [toolbarType, setToolbarType] = React.useState("all");
  const [toolbarStatus, setToolbarStatus] = React.useState("all");
  const [pagination, setPagination] = React.useState<PaginationState>({
    pageIndex: 0,
    pageSize: 20,
  });

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

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

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

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

    void loadPromoCodes(nextFilters, true);
  };

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

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

  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 PromoClientFilters>(
    key: K,
    value: PromoClientFilters[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="promo-toolbar-type" className="text-xs">
              Type
            </Label>
            <Select value={toolbarType} onValueChange={setToolbarType}>
              <SelectTrigger id="promo-toolbar-type" className="h-9 w-[180px]">
                <SelectValue placeholder="Type" />
              </SelectTrigger>
              <SelectContent>
                <SelectGroup>
                  {typeOptions.map((option) => (
                    <SelectItem key={option.value} value={option.value}>
                      {option.label}
                    </SelectItem>
                  ))}
                </SelectGroup>
              </SelectContent>
            </Select>
          </div>
          <div className="space-y-1">
            <Label htmlFor="promo-toolbar-status" className="text-xs">
              Status
            </Label>
            <Select value={toolbarStatus} onValueChange={setToolbarStatus}>
              <SelectTrigger id="promo-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 promo codes match your filters."
        renderFilterCell={(header) => renderFilterCell(header, clientFilters, updateClientFilter)}
      />

      <DataTablePagination
        table={table}
        totalRows={filteredData.length}
        itemNoun="promo code"
        idPrefix="promo-codes"
      />
    </div>
  );
}

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

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

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

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

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

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

  if (columnId === "dateStart") {
    return (
      <TableCell key={header.id} className="p-2">
        <div className="flex items-center gap-1">
          <Select
            value={filters.dateStartComparison}
            onValueChange={(value) =>
              updateFilter("dateStartComparison", value as DateComparison)
            }
          >
            <SelectTrigger className="h-8 w-14 bg-background px-2 text-xs">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {DATE_COMPARISONS.map((opt) => (
                <SelectItem key={opt.value} value={opt.value}>
                  {opt.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
          <Input
            type="date"
            value={filters.dateStart}
            onChange={(event) => updateFilter("dateStart", event.target.value)}
            className="h-8 flex-1 bg-background text-xs"
          />
        </div>
      </TableCell>
    );
  }

  if (columnId === "dateEnd") {
    return (
      <TableCell key={header.id} className="p-2">
        <div className="flex items-center gap-1">
          <Select
            value={filters.dateEndComparison}
            onValueChange={(value) => updateFilter("dateEndComparison", value as DateComparison)}
          >
            <SelectTrigger className="h-8 w-14 bg-background px-2 text-xs">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              {DATE_COMPARISONS.map((opt) => (
                <SelectItem key={opt.value} value={opt.value}>
                  {opt.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
          <Input
            type="date"
            value={filters.dateEnd}
            onChange={(event) => updateFilter("dateEnd", event.target.value)}
            className="h-8 flex-1 bg-background text-xs"
          />
        </div>
      </TableCell>
    );
  }

  return null;
}

export function PromoCodesHeaderActions({ data }: { data: PromoCodeRow[] }) {
  return (
    <DataTableHeaderActions
      createHref="/dashboard/plans-orders/promo-codes/create"
      createLabel="Create new"
      onExport={() => exportPromoCodes(data)}
    />
  );
}
