"use client";

import { useMemo, useState } from "react";
import {
  useReactTable,
  getCoreRowModel,
  getFilteredRowModel,
  getSortedRowModel,
  getPaginationRowModel,
  flexRender,
  type SortingState,
  type PaginationState,
  type ColumnDef,
} from "@tanstack/react-table";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/app/shadcn_components/ui/table";
import { Input } from "@/app/shadcn_components/ui/input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
} from "@/app/shadcn_components/ui/select";
import { Search, ChevronLeft, ChevronRight, Download } from "lucide-react";
import { createDocumentTableColumns } from "./DocumentTableColumns";
import ContractorUploadModal from "./ContractorUploadModal";
import type { ClassifiedDeal, DocStatusMap, PortfolioCapabilityType, ApprovalsByDeal } from "./types";

type RetroAssessmentFilter = "all" | "none" | "partial" | "complete";
type InstallStatusFilter = "all" | "none" | "hasDocs" | "partial" | "complete";

/**
 * Row-selection wiring for bulk document download. When present, the table
 * shows a tick column; select-all operates over every filtered row (all pages),
 * not just the visible page. Rows without a landlord property id are un-tickable
 * — documents are matched by landlord property id, so there is nothing to zip.
 */
export interface DocumentSelection {
  selectedIds: Set<string>;
  onToggle: (landlordPropertyId: string) => void;
  onSetMany: (landlordPropertyIds: string[], selected: boolean) => void;
}

interface DocumentTableProps {
  data: ClassifiedDeal[];
  onOpenDrawer: (dealId: string, uprn: string | null, landlordPropertyId: string | null, dealname: string | null, batch: string | null, batchDescription: string | null) => void;
  docStatusMap: DocStatusMap;
  portfolioId: string;
  userCapability: PortfolioCapabilityType;
  approvalsByDeal?: ApprovalsByDeal;
  selection?: DocumentSelection;
}

function escapeCell(value: unknown): string {
  if (value === null || value === undefined) return "";
  const str =
    value instanceof Date
      ? value.toLocaleDateString("en-GB")
      : String(value);
  return str.includes(",") || str.includes('"') || str.includes("\n")
    ? `"${str.replace(/"/g, '""')}"`
    : str;
}

export default function DocumentTable({ data, onOpenDrawer, docStatusMap, portfolioId, userCapability, approvalsByDeal, selection }: DocumentTableProps) {
  const [globalFilter, setGlobalFilter] = useState("");
  const [retroAssessmentFilter, setRetroAssessmentFilter] = useState<RetroAssessmentFilter>("all");
  const [installStatusFilter, setInstallStatusFilter] = useState<InstallStatusFilter>("all");
  const [sorting, setSorting] = useState<SortingState>([]);
  const [pagination, setPagination] = useState<PaginationState>({
    pageIndex: 0,
    pageSize: 25,
  });
  const [uploadDeal, setUploadDeal] = useState<ClassifiedDeal | null>(null);

  const filteredData = useMemo(() => {
    return data.filter((d) => {
      const status = docStatusMap[d.dealId];

      if (retroAssessmentFilter !== "all") {
        if (retroAssessmentFilter === "none" && !(!status || !status.hasSurveyDocs)) return false;
        if (retroAssessmentFilter === "partial" && !(status?.hasSurveyDocs && !status.isSurveyComplete)) return false;
        if (retroAssessmentFilter === "complete" && !status?.isSurveyComplete) return false;
      }

      if (installStatusFilter !== "all") {
        const s = status?.installStatus ?? "none";
        if (installStatusFilter === "none" && s !== "none") return false;
        if (installStatusFilter === "hasDocs" && s !== "hasDocs") return false;
        if (installStatusFilter === "partial" && s !== "partial") return false;
        if (installStatusFilter === "complete" && s !== "all") return false;
      }

      return true;
    });
  }, [data, retroAssessmentFilter, installStatusFilter, docStatusMap]);

  const baseColumns = useMemo(
    () => createDocumentTableColumns(
      onOpenDrawer,
      docStatusMap,
      userCapability.includes("contractor") ? setUploadDeal : undefined,
    ),
    [onOpenDrawer, docStatusMap, userCapability],
  );

  // Prepend a tick column when in selection mode. Recomputed when `selection`
  // changes (a fresh Set per toggle) so checkbox state stays live.
  const columns: ColumnDef<ClassifiedDeal>[] = useMemo(() => {
    if (!selection) return baseColumns;
    const selectColumn: ColumnDef<ClassifiedDeal> = {
      id: "select",
      enableSorting: false,
      enableGlobalFilter: false,
      header: ({ table }) => {
        // Header ticks the current page; the banner below offers all pages.
        const pageIds = table
          .getRowModel()
          .rows.map((r) => r.original.landlordPropertyId)
          .filter((id): id is string => !!id);
        const allSelected =
          pageIds.length > 0 && pageIds.every((id) => selection.selectedIds.has(id));
        const someSelected = pageIds.some((id) => selection.selectedIds.has(id));
        return (
          <input
            type="checkbox"
            aria-label="Select all properties on this page"
            checked={allSelected}
            ref={(el) => {
              if (el) el.indeterminate = someSelected && !allSelected;
            }}
            onChange={() => selection.onSetMany(pageIds, !allSelected)}
            className="h-4 w-4 accent-brandblue align-middle"
          />
        );
      },
      cell: ({ row }) => {
        const id = row.original.landlordPropertyId;
        if (!id) {
          return (
            <span
              title="No landlord property id — no documents to include"
              className="inline-block h-4 w-4 rounded border border-gray-200 bg-gray-100 align-middle"
            />
          );
        }
        return (
          <input
            type="checkbox"
            aria-label={`Select ${id}`}
            checked={selection.selectedIds.has(id)}
            onChange={() => selection.onToggle(id)}
            className="h-4 w-4 accent-brandblue align-middle"
          />
        );
      },
    };
    return [selectColumn, ...baseColumns];
  }, [baseColumns, selection]);

  const table = useReactTable({
    data: filteredData,
    columns,
    state: { globalFilter, sorting, pagination },
    onGlobalFilterChange: setGlobalFilter,
    onSortingChange: setSorting,
    onPaginationChange: setPagination,
    getCoreRowModel: getCoreRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    globalFilterFn: "includesString",
  });

  const downloadCsv = () => {
    const rows = table.getFilteredRowModel().rows;
    const header = "Address,Landlord ID,Retrofit Assessment Status,Install Docs Status,Group,Group Description";
    const body = rows
      .map((row) => {
        const status = docStatusMap[row.original.dealId];
        const retroStatus = status?.isSurveyComplete
          ? "Complete"
          : status?.hasSurveyDocs
            ? "Partial"
            : "No Docs";
        const installStatusMap: Record<string, string> = {
          all: "All Measures",
          partial: "Some Measures",
          hasDocs: "Has Docs",
          none: "No Docs",
        };
        const installStatus = installStatusMap[status?.installStatus ?? "none"];
        return [
          escapeCell(row.original.dealname),
          escapeCell(row.original.landlordPropertyId),
          retroStatus,
          installStatus,
          escapeCell(row.original.batch),
          escapeCell(row.original.batchDescription),
        ].join(",");
      })
      .join("\n");
    const blob = new Blob([header + "\n" + body], { type: "text/csv;charset=utf-8;" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = "document-management.csv";
    a.click();
    URL.revokeObjectURL(url);
  };

  const pageCount = table.getPageCount();
  const currentPage = table.getState().pagination.pageIndex + 1;
  const totalFiltered = table.getFilteredRowModel().rows.length;

  // "Select all across pages" banner: shown when the whole current page is
  // ticked and there are more filtered rows than fit on it (Gmail-style).
  const pageSelectableIds = selection
    ? table
        .getRowModel()
        .rows.map((r) => r.original.landlordPropertyId)
        .filter((id): id is string => !!id)
    : [];
  const filteredSelectableIds = selection
    ? table
        .getFilteredRowModel()
        .rows.map((r) => r.original.landlordPropertyId)
        .filter((id): id is string => !!id)
    : [];
  const pageFullySelected =
    pageSelectableIds.length > 0 &&
    pageSelectableIds.every((id) => selection!.selectedIds.has(id));
  const allFilteredSelected =
    filteredSelectableIds.length > 0 &&
    filteredSelectableIds.every((id) => selection!.selectedIds.has(id));
  const showSelectAllBanner =
    !!selection &&
    pageFullySelected &&
    filteredSelectableIds.length > pageSelectableIds.length;

  const retroAssessmentLabel: Record<RetroAssessmentFilter, string> = {
    all: "All retrofit statuses",
    none: "No Retrofit Docs",
    partial: "Partial Retrofit Docs",
    complete: "Complete Retrofit Docs",
  };

  const installStatusLabel: Record<InstallStatusFilter, string> = {
    all: "All install statuses",
    none: "No Install Docs",
    hasDocs: "Has Install Docs",
    partial: "Some Measures",
    complete: "All Measures",
  };

  return (
    <div className="space-y-3">
      {/* Toolbar */}
      <div className="flex flex-col sm:flex-row gap-3 items-start sm:items-center">
        {/* Search */}
        <div className="relative flex-1 min-w-0">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400 pointer-events-none" />
          <Input
            value={globalFilter}
            onChange={(e) => {
              setGlobalFilter(e.target.value);
              setPagination((p) => ({ ...p, pageIndex: 0 }));
            }}
            placeholder="Search address, landlord ID…"
            className="pl-9 h-9 text-sm border-gray-200 focus:border-brandblue/40 focus:ring-brandblue/20"
          />
        </div>

        {/* Retrofit assessment filter */}
        <Select
          value={retroAssessmentFilter}
          onValueChange={(v) => {
            setRetroAssessmentFilter(v as RetroAssessmentFilter);
            setPagination((p) => ({ ...p, pageIndex: 0 }));
          }}
        >
          <SelectTrigger className="h-9 w-[210px] text-sm border-gray-200 shrink-0">
            {retroAssessmentLabel[retroAssessmentFilter]}
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="all">All retrofit statuses</SelectItem>
            <SelectItem value="none">No Retrofit Docs</SelectItem>
            <SelectItem value="partial">Partial Retrofit Docs</SelectItem>
            <SelectItem value="complete">Complete Retrofit Docs</SelectItem>
          </SelectContent>
        </Select>

        {/* Install docs filter */}
        <Select
          value={installStatusFilter}
          onValueChange={(v) => {
            setInstallStatusFilter(v as InstallStatusFilter);
            setPagination((p) => ({ ...p, pageIndex: 0 }));
          }}
        >
          <SelectTrigger className="h-9 w-[190px] text-sm border-gray-200 shrink-0">
            {installStatusLabel[installStatusFilter]}
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="all">All install statuses</SelectItem>
            <SelectItem value="none">No Install Docs</SelectItem>
            <SelectItem value="hasDocs">Has Install Docs</SelectItem>
            <SelectItem value="partial">Some Measures</SelectItem>
            <SelectItem value="complete">All Measures</SelectItem>
          </SelectContent>
        </Select>

        {/* Download CSV */}
        <button
          onClick={downloadCsv}
          className="inline-flex items-center gap-2 h-9 px-3 rounded-lg border border-gray-200 bg-white text-sm font-medium text-gray-600 hover:border-brandblue/30 hover:text-brandblue transition-colors shrink-0"
        >
          <Download className="h-3.5 w-3.5" />
          CSV
        </button>
      </div>

      {/* Result count */}
      <p className="text-xs text-gray-400">
        Showing{" "}
        <span className="font-semibold text-gray-600">
          {Math.min(
            table.getState().pagination.pageSize,
            totalFiltered - table.getState().pagination.pageIndex * table.getState().pagination.pageSize,
          )}
        </span>{" "}
        of{" "}
        <span className="font-semibold text-gray-600">{totalFiltered}</span>{" "}
        {(retroAssessmentFilter !== "all" || installStatusFilter !== "all") ? "(filtered) " : ""}
        propert{totalFiltered === 1 ? "y" : "ies"}
      </p>

      {/* Select-all-across-pages banner */}
      {showSelectAllBanner && (
        <div className="flex flex-wrap items-center gap-2 rounded-lg border border-brandblue/20 bg-brandlightblue/20 px-3.5 py-2 text-[13px] text-brandblue">
          {allFilteredSelected ? (
            <>
              <span>
                All <span className="font-semibold">{filteredSelectableIds.length}</span>{" "}
                matching propert{filteredSelectableIds.length === 1 ? "y is" : "ies are"}{" "}
                selected.
              </span>
              <button
                onClick={() => selection!.onSetMany(filteredSelectableIds, false)}
                className="font-semibold underline hover:text-brandblue/80"
              >
                Clear selection
              </button>
            </>
          ) : (
            <>
              <span>
                All <span className="font-semibold">{pageSelectableIds.length}</span> on this
                page selected.
              </span>
              <button
                onClick={() => selection!.onSetMany(filteredSelectableIds, true)}
                className="font-semibold underline hover:text-brandblue/80"
              >
                Select all {filteredSelectableIds.length} across pages
              </button>
            </>
          )}
        </div>
      )}

      {/* Table */}
      <div className="rounded-xl border border-gray-200 overflow-hidden shadow-sm">
        <div className="overflow-x-auto">
          <Table>
            <TableHeader>
              {table.getHeaderGroups().map((headerGroup) => (
                <TableRow
                  key={headerGroup.id}
                  className="bg-gray-50/80 hover:bg-gray-50/80 border-b border-gray-200"
                >
                  {headerGroup.headers.map((header) => (
                    <TableHead key={header.id} className="h-10 px-4 first:pl-5 last:pr-5">
                      {header.isPlaceholder
                        ? null
                        : flexRender(header.column.columnDef.header, header.getContext())}
                    </TableHead>
                  ))}
                </TableRow>
              ))}
            </TableHeader>
            <TableBody>
              {table.getRowModel().rows.length ? (
                table.getRowModel().rows.map((row, i) => (
                  <TableRow
                    key={row.id}
                    className={`border-b border-gray-100 transition-colors hover:bg-brandlightblue/10 ${
                      i % 2 === 0 ? "bg-white" : "bg-gray-50/30"
                    }`}
                  >
                    {row.getVisibleCells().map((cell) => (
                      <TableCell key={cell.id} className="py-3 px-4 first:pl-5 last:pr-5">
                        {flexRender(cell.column.columnDef.cell, cell.getContext())}
                      </TableCell>
                    ))}
                  </TableRow>
                ))
              ) : (
                <TableRow>
                  <TableCell
                    colSpan={columns.length}
                    className="h-32 text-center text-sm text-gray-400"
                  >
                    No properties match the current filters.
                  </TableCell>
                </TableRow>
              )}
            </TableBody>
          </Table>
        </div>
      </div>

      {/* Contractor upload modal */}
      {uploadDeal && (
        <ContractorUploadModal
          deal={uploadDeal}
          portfolioId={portfolioId}
          onClose={() => setUploadDeal(null)}
          docStatusMap={docStatusMap}
          approvedMeasures={approvalsByDeal?.[uploadDeal.dealId] ?? []}
        />
      )}

      {/* Pagination */}
      {pageCount > 1 && (
        <div className="flex items-center justify-between pt-1">
          <div className="flex items-center gap-2">
            <span className="text-xs text-gray-500">Rows per page:</span>
            <Select
              value={String(table.getState().pagination.pageSize)}
              onValueChange={(v) => table.setPageSize(Number(v))}
            >
              <SelectTrigger className="h-7 w-16 text-xs border-gray-200">
                {table.getState().pagination.pageSize}
              </SelectTrigger>
              <SelectContent>
                {[10, 25, 50, 100].map((n) => (
                  <SelectItem key={n} value={String(n)} className="text-xs">
                    {n}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>

          <div className="flex items-center gap-3">
            <span className="text-xs text-gray-500">
              Page {currentPage} of {pageCount}
            </span>
            <div className="flex gap-1">
              <button
                onClick={() => table.previousPage()}
                disabled={!table.getCanPreviousPage()}
                className="h-7 w-7 flex items-center justify-center rounded-lg border border-gray-200 text-gray-500 hover:border-brandblue/30 hover:text-brandblue disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
              >
                <ChevronLeft className="h-3.5 w-3.5" />
              </button>
              <button
                onClick={() => table.nextPage()}
                disabled={!table.getCanNextPage()}
                className="h-7 w-7 flex items-center justify-center rounded-lg border border-gray-200 text-gray-500 hover:border-brandblue/30 hover:text-brandblue disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
              >
                <ChevronRight className="h-3.5 w-3.5" />
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
