"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 { filterPlanRowsClient } 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 { MembershipPlansResult } from "../_lib/membership-plans-server-api";
import { fetchMembershipPlans } from "./api/membership-plans.api";
import { createPlanColumns } from "./columns";
import {
  PLAN_STATUS_OPTIONS,
  emptyPlanClientFilters,
  type PlanClientFilters,
  type PlanRow,
} from "./schema";

const ALL_PLAN_TYPES_VALUE = "__all__";

function toPlanTypeSelectValue(type: string) {
  return type || ALL_PLAN_TYPES_VALUE;
}

function fromPlanTypeSelectValue(value: string) {
  return value === ALL_PLAN_TYPES_VALUE ? "" : value;
}

function exportPlans(rows: PlanRow[]) {
  downloadCsv({
    filename: "membership-plans",
    headers: [
      "ID",
      "Name",
      "Plan Type",
      "Price",
      "Currency",
      "Billing",
      "Status",
      "Sub Users",
      "Date Added",
    ],
    rows,
    toRow: (row) => [
      row.id,
      row.name,
      row.planTypeLabel,
      row.priceFormatted,
      row.currency,
      row.billingCycleLabel,
      row.statusLabel,
      row.subscribers,
      row.dateAdded,
    ],
  });
}

type PlansTableProps = {
  initialData: MembershipPlansResult;
  initialErrorMessage?: string | null;
};

export function PlansTable({
  initialData,
  initialErrorMessage = null,
}: PlansTableProps) {
  const [data, setData] = React.useState(initialData);
  const [errorMessage, setErrorMessage] = React.useState(initialErrorMessage);
  const [isRefreshing, setIsRefreshing] = React.useState(false);
  const [clientFilters, setClientFilters] =
    React.useState<PlanClientFilters>(emptyPlanClientFilters);
  const [toolbarType, setToolbarType] = React.useState(toPlanTypeSelectValue(initialData.filters.type));
  const [toolbarStatus, setToolbarStatus] = React.useState("all");
  const [toolbarFromDate, setToolbarFromDate] = React.useState(initialData.filters.from_date);
  const [toolbarToDate, setToolbarToDate] = React.useState(initialData.filters.to_date);
  const [pagination, setPagination] = React.useState<PaginationState>({
    pageIndex: 0,
    pageSize: 20,
  });

  const planTypeOptions = React.useMemo(
    () => data.filterOptions.planTypes,
    [data.filterOptions.planTypes],
  );

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

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

  const applyToolbarSearch = () => {
    const nextServerFilters = {
      type: fromPlanTypeSelectValue(toolbarType),
      from_date: toolbarFromDate,
      to_date: toolbarToDate,
    };

    setClientFilters((prev) => ({
      ...prev,
      status: toolbarStatus,
    }));
    void loadPlans(nextServerFilters, true);
  };

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

  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 PlanClientFilters>(
    key: K,
    value: PlanClientFilters[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="plans-toolbar-type" className="text-xs">
              Plan type
            </Label>
            <Select value={toolbarType} onValueChange={setToolbarType}>
              <SelectTrigger id="plans-toolbar-type" className="h-9 w-[180px]">
                <SelectValue placeholder="Type" />
              </SelectTrigger>
              <SelectContent>
                <SelectGroup>
                  <SelectItem value={ALL_PLAN_TYPES_VALUE}>All types</SelectItem>
                  {planTypeOptions.map((option) => (
                    <SelectItem key={option} value={option.toLowerCase()}>
                      {option}
                    </SelectItem>
                  ))}
                </SelectGroup>
              </SelectContent>
            </Select>
          </div>
          <div className="space-y-1">
            <Label htmlFor="plans-toolbar-from-date" className="text-xs">
              From
            </Label>
            <Input
              id="plans-toolbar-from-date"
              type="date"
              value={toolbarFromDate}
              onChange={(event) => setToolbarFromDate(event.target.value)}
              className="h-9 w-[160px]"
            />
          </div>
          <div className="space-y-1">
            <Label htmlFor="plans-toolbar-to-date" className="text-xs">
              To
            </Label>
            <Input
              id="plans-toolbar-to-date"
              type="date"
              value={toolbarToDate}
              onChange={(event) => setToolbarToDate(event.target.value)}
              className="h-9 w-[160px]"
            />
          </div>
          <div className="space-y-1">
            <Label htmlFor="plans-toolbar-status" className="text-xs">
              Status
            </Label>
            <Select value={toolbarStatus} onValueChange={setToolbarStatus}>
              <SelectTrigger id="plans-toolbar-status" className="h-9 w-[180px]">
                <SelectValue placeholder="Status" />
              </SelectTrigger>
              <SelectContent>
                <SelectGroup>
                  {PLAN_STATUS_OPTIONS.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}
          >
            {isRefreshing ? "Searching..." : "Search"}
          </Button>
        </div>
      </div>

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

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

function renderFilterCell(
  header: Header<PlanRow, unknown>,
  filters: PlanClientFilters,
  updateFilter: <K extends keyof PlanClientFilters>(key: K, value: PlanClientFilters[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="Plan name"
          className="h-8 bg-background text-xs"
        />
      </TableCell>
    );
  }

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

  return null;
}

export function PlansHeaderActions({ data }: { data: PlanRow[] }) {
  return (
    <DataTableHeaderActions
      createHref="/dashboard/plans-orders/membership-plans/create"
      onExport={() => exportPlans(data)}
    />
  );
}
