"use client";

import * as React from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useSession } from "next-auth/react";
import {
  CheckCircle2,
  Clock,
  FileDown,
  FileSpreadsheet,
  FilterX,
  Loader2,
  Receipt,
  RefreshCw,
  Search,
} from "lucide-react";
import { format } from "date-fns";
import { toast } from "sonner";

import { useGetProfileQuery } from "@/api/rtk/auth-api";
import {
  buildTransactionsExcelExportUrl,
  buildTransactionsPdfExportUrl,
  type TransactionsExportParams,
} from "@/api/rtk/transactions-api";
import { useTransactionsCatalog } from "@/hooks/use-transactions-catalog";
import { Button } from "@/components/ui/button";
import { ButtonGroup } from "@/components/ui/button-group";
import { DateRangePicker } from "@/components/ui/date-range-picker";
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import { Input } from "@/components/ui/input";
import { Loading } from "@/components/ui/loading";
import { NoDataFound } from "@/components/ui/no-data-found";
import { ReactSelect } from "@/components/ui/react-select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { useTeamsCatalog } from "@/hooks/use-teams-catalog";
import {
  formatLedgerDealLabel,
  formatTeamLabelForUi,
} from "@/lib/deal-display";
import {
  canSeeAllTeamsInApp,
  canViewTransactions,
  filterTeamsVisibleToUser,
  type PermissionSource,
} from "@/lib/permissions";
import { TransactionsSummaryStrip } from "@/components/transactions/transactions-summary";
import { useBlobExportWorker } from "@/hooks/use-blob-export-worker";
import { cn } from "@/lib/utils";

function formatMoney(amount: number): string {
  return new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  }).format(amount);
}

function formatKindLabel(kind: string): string {
  const k = kind.trim();
  if (!k) return "—";
  return k.charAt(0).toUpperCase() + k.slice(1);
}

function formatTimestamp(iso: string | null | undefined): string {
  if (!iso) return "—";
  try {
    return format(new Date(iso), "MMM d, yyyy h:mm a");
  } catch {
    return "—";
  }
}

export default function TransactionsPage() {
  const router = useRouter();
  const { data: session } = useSession();
  const backendUser = (session as { backendUser?: PermissionSource } | null)
    ?.backendUser;
  const { data: profile } = useGetProfileQuery();
  const permissionSource: PermissionSource = backendUser ?? profile ?? null;
  const { items: teams = [] } = useTeamsCatalog({ skip: !permissionSource });
  const viewerId = profile?.id ?? "";

  const allowed = React.useMemo(
    () => canViewTransactions(permissionSource),
    [permissionSource],
  );

  React.useEffect(() => {
    if (!permissionSource) return;
    if (!allowed) router.replace("/");
  }, [permissionSource, allowed, router]);

  const visibleTeams = React.useMemo(
    () => filterTeamsVisibleToUser(teams, viewerId, permissionSource),
    [teams, viewerId, permissionSource],
  );

  const teamFilterOptions = React.useMemo(() => {
    const opts = visibleTeams.map((t) => ({
      value: t.id,
      label: formatTeamLabelForUi(t.name),
    }));
    if (canSeeAllTeamsInApp(permissionSource)) {
      return [{ value: "all", label: "All teams" }, ...opts];
    }
    return opts;
  }, [visibleTeams, permissionSource]);

  const [teamId, setTeamId] = React.useState("all");
  const [from, setFrom] = React.useState("");
  const [to, setTo] = React.useState("");
  const [ledgerStatus, setLedgerStatus] = React.useState<
    "all" | "paid" | "pending"
  >("all");
  const [search, setSearch] = React.useState("");
  const [searchDebounced, setSearchDebounced] = React.useState("");
  const [page, setPage] = React.useState(1);

  React.useEffect(() => {
    const t = window.setTimeout(() => setSearchDebounced(search.trim()), 300);
    return () => window.clearTimeout(t);
  }, [search]);

  React.useEffect(() => {
    setPage(1);
  }, [teamId, from, to, ledgerStatus, searchDebounced]);

  React.useEffect(() => {
    if (teamFilterOptions.length === 0) return;
    setTeamId((prev) => {
      if (teamFilterOptions.some((opt) => opt.value === prev)) return prev;
      return teamFilterOptions[0]?.value ?? "all";
    });
  }, [teamFilterOptions]);

  const hasActiveFilters = React.useMemo(
    () =>
      (teamId !== "all" && Boolean(teamId)) ||
      Boolean(from.trim() || to.trim()) ||
      ledgerStatus !== "all" ||
      search.trim() !== "",
    [teamId, from, to, ledgerStatus, search],
  );

  const handleClearFilters = React.useCallback(() => {
    const defaultTeam =
      teamFilterOptions.find((opt) => opt.value === "all")?.value ??
      teamFilterOptions[0]?.value ??
      "all";
    setTeamId(defaultTeam);
    setFrom("");
    setTo("");
    setLedgerStatus("all");
    setSearch("");
    setSearchDebounced("");
    setPage(1);
  }, [teamFilterOptions]);

  const exportParams = React.useMemo<TransactionsExportParams>(
    () => ({
      teamId: teamId !== "all" ? teamId : undefined,
      from: from || undefined,
      to: to || undefined,
      ledgerStatus:
        ledgerStatus && ledgerStatus !== "all"
          ? (ledgerStatus as "paid" | "pending")
          : undefined,
      search: searchDebounced || undefined,
    }),
    [teamId, from, to, ledgerStatus, searchDebounced],
  );

  const queryParams = React.useMemo(
    () => ({
      ...exportParams,
      page,
      limit: 50,
    }),
    [exportParams, page],
  );

  const {
    items,
    total,
    summary,
    limit,
    isLoading,
    isFetching,
    refetch,
  } = useTransactionsCatalog(queryParams, { skip: !allowed });

  const refreshing = isFetching && !isLoading;

  const handleRefresh = React.useCallback(() => {
    void refetch();
  }, [refetch]);

  const { downloadFromUrl } = useBlobExportWorker();
  const [exportingExcel, setExportingExcel] = React.useState(false);
  const [exportingPdf, setExportingPdf] = React.useState(false);

  const exportDisabled = total === 0 && !isLoading;
  const exporting = exportingExcel || exportingPdf;

  const handleExportExcel = React.useCallback(async () => {
    if (exportDisabled || exporting) {
      if (exportDisabled) {
        toast.error("No transactions to export for the current filters.");
      }
      return;
    }
    const stamp = new Date().toISOString().slice(0, 10);
    const toastId = toast.loading("Generating Excel export…");
    setExportingExcel(true);
    try {
      await downloadFromUrl(
        buildTransactionsExcelExportUrl(exportParams),
        `transactions-export_${stamp}.xlsx`,
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      );
      toast.success("Excel ready — check your downloads", { id: toastId });
    } catch (err) {
      const message =
        err instanceof Error ? err.message : "Could not generate the Excel file.";
      toast.error(message, { id: toastId });
    } finally {
      setExportingExcel(false);
    }
  }, [exportDisabled, exporting, downloadFromUrl, exportParams]);

  const handleExportPdf = React.useCallback(async () => {
    if (exportDisabled || exporting) {
      if (exportDisabled) {
        toast.error("No transactions to export for the current filters.");
      }
      return;
    }
    const stamp = new Date().toISOString().slice(0, 10);
    const toastId = toast.loading("Generating PDF export…");
    setExportingPdf(true);
    try {
      await downloadFromUrl(
        buildTransactionsPdfExportUrl(exportParams),
        `transactions-export_${stamp}.pdf`,
        "application/pdf",
      );
      toast.success("PDF ready — check your downloads", { id: toastId });
    } catch (err) {
      const message =
        err instanceof Error ? err.message : "Could not generate the PDF.";
      toast.error(message, { id: toastId });
    } finally {
      setExportingPdf(false);
    }
  }, [exportDisabled, exporting, downloadFromUrl, exportParams]);
 
  const totalPages = Math.max(1, Math.ceil(total / limit));

  if (!permissionSource) {
    return <Loading variant="api" layout="page" message="Loading transactions..." />;
  }

  if (!allowed) {
    return null;
  }

  return (
    <div className="flex min-h-0 flex-1 flex-col gap-4 p-4 md:p-6">
      <header className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
        <div className="flex items-start gap-3">
          <div className="flex size-10 shrink-0 items-center justify-center rounded-xl bg-[#1d1d39] text-white">
            <Receipt className="size-5" aria-hidden />
          </div>
          <div>
            <h1 className="font-['Lexend'] text-xl font-bold text-[#101828]">
              Transactions
            </h1>
            <p className="mt-1 max-w-xl text-sm text-[#575a62]">
              Payment ledger across leads you can access. Edits are made on deal
              payment structures.
            </p>
          </div>
        </div>
        <TooltipProvider delayDuration={400}>
          <ButtonGroup
            className="shrink-0"
            aria-label="Transaction actions"
          >
            <Tooltip>
              <TooltipTrigger asChild>
                <Button
                  type="button"
                  variant="outline"
                  size="icon-sm"
                  className="border-black/10 bg-white text-[#575a62] hover:border-accent hover:text-accent"
                  disabled={refreshing}
                  onClick={handleRefresh}
                  aria-label={
                    refreshing ? "Refreshing transactions" : "Refresh transactions"
                  }
                >
                  <RefreshCw
                    className={cn("size-4", refreshing && "animate-spin")}
                    aria-hidden
                  />
                </Button>
              </TooltipTrigger>
              <TooltipContent>
                <p>{refreshing ? "Refreshing…" : "Refresh"}</p>
              </TooltipContent>
            </Tooltip>
            <Tooltip>
              <TooltipTrigger asChild>
                <Button
                  type="button"
                  variant="outline"
                  size="icon-sm"
                  className="border-black/10 bg-white text-[#575a62] hover:border-accent hover:text-accent"
                  disabled={exportDisabled || exporting}
                  onClick={() => void handleExportPdf()}
                  aria-label={
                    exportingPdf ? "Exporting PDF" : "Export transactions as PDF"
                  }
                >
                  {exportingPdf ? (
                    <Loader2 className="size-4 animate-spin" aria-hidden />
                  ) : (
                    <FileDown className="size-4" aria-hidden />
                  )}
                </Button>
              </TooltipTrigger>
              <TooltipContent>
                <p>{exportingPdf ? "Exporting PDF…" : "Export as PDF"}</p>
              </TooltipContent>
            </Tooltip>
            <Tooltip>
              <TooltipTrigger asChild>
                <Button
                  type="button"
                  variant="outline"
                  size="icon-sm"
                  className="border-black/10 bg-white text-[#575a62] hover:border-accent hover:text-accent"
                  disabled={exportDisabled || exporting}
                  onClick={() => void handleExportExcel()}
                  aria-label={
                    exportingExcel
                      ? "Exporting Excel"
                      : "Export transactions as Excel"
                  }
                >
                  {exportingExcel ? (
                    <Loader2 className="size-4 animate-spin" aria-hidden />
                  ) : (
                    <FileSpreadsheet className="size-4" aria-hidden />
                  )}
                </Button>
              </TooltipTrigger>
              <TooltipContent>
                <p>{exportingExcel ? "Exporting Excel…" : "Export as Excel"}</p>
              </TooltipContent>
            </Tooltip>
          </ButtonGroup>
        </TooltipProvider>
      </header>

      <div className="flex flex-wrap items-end gap-2 rounded-xl border border-black/6 bg-white/60 p-2.5 backdrop-blur-sm">
        <div className="flex min-w-[120px] flex-col gap-0.5">
          <span className="text-[10px] font-semibold uppercase tracking-wide text-[#575a62]">
            Team
          </span>
          <ReactSelect
            size="sm"
            value={teamId || "all"}
            onValueChange={setTeamId}
            options={teamFilterOptions}
            placeholder="Select team"
            aria-label="Filter by team"
            triggerClassName="h-8 min-h-8 min-w-[150px] text-xs sm:w-[180px] min-[1500px]:!h-7 min-[1500px]:!min-h-7 min-[1500px]:!max-h-7 min-[1500px]:w-[96px] min-[1500px]:max-w-[108px] min-[1500px]:min-w-[96px] min-[1500px]:px-2.5 min-[1500px]:text-[11px] min-[1500px]:[&_svg]:!size-3"
          />
        </div>

        <div className="flex min-w-[160px] flex-col gap-0.5 sm:min-w-[200px]">
          <span className="text-[10px] font-semibold uppercase tracking-wide text-[#575a62]">
            Period
          </span>
          <DateRangePicker
            value={{ from: from || undefined, to: to || undefined }}
            onChange={({ from: nextFrom, to: nextTo }) => {
              setFrom(nextFrom ?? "");
              setTo(nextTo ?? "");
            }}
            placeholder="Select period"
            triggerClassName="h-8 min-h-8 py-0 text-xs"
          />
        </div>

        <div className="flex min-w-[100px] flex-col gap-0.5">
          <span className="text-[10px] font-semibold uppercase tracking-wide text-[#575a62]">
            Status
          </span>
          <ReactSelect
            size="sm"
            value={ledgerStatus || "all"}
            onValueChange={(v) =>
              setLedgerStatus(v as "all" | "paid" | "pending")
            }
            options={[
              { value: "all", label: "All statuses" },
              { value: "paid", label: "Paid" },
              { value: "pending", label: "Pending" },
            ]}
            placeholder="Status"
            aria-label="Filter by status"
            triggerClassName="h-8 min-h-8 w-[120px] text-xs"
          />
        </div>

        <div className="flex min-w-[160px] flex-1 flex-col gap-0.5">
          <span className="text-[10px] font-semibold uppercase tracking-wide text-[#575a62]">
            Search
          </span>
          <div className="relative">
            <Search
              className="pointer-events-none absolute left-2 top-1/2 size-3.5 -translate-y-1/2 text-[#575a62]"
              aria-hidden
            />
            <Input
              type="search"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder="Search lead/deal, description, kind, or key"
              aria-label="Search transactions"
              className="h-8 min-h-8 rounded-lg py-1 pl-8 text-xs"
            />
          </div>
        </div>

        {hasActiveFilters && (
          <Button
            type="button"
            variant="outline"
            size="sm"
            className="h-8 min-h-8 shrink-0 gap-1 border-black/10 bg-white px-2.5 text-xs text-[#575a62] hover:border-accent hover:text-accent"
            onClick={handleClearFilters}
            aria-label="Clear filters"
          >
            <FilterX className="size-3.5 shrink-0" aria-hidden />
            Clear filters
          </Button>
        )}
      </div>

      <TransactionsSummaryStrip
        total={total}
        summary={summary}
        isLoading={isLoading}
        isUpdating={isFetching && !isLoading}
      />

      <div className="min-h-0 flex-1 overflow-hidden">
        {isLoading ? (
          <Loading variant="api" layout="section" message="Loading transactions..." />
        ) : items.length === 0 ? (
          <NoDataFound
            message="No transactions"
            description="No payment transactions match your filters."
          />
        ) : (
          <Table className="min-w-[1120px]">
              <TableHeader>
                <TableRow>
                  <TableHead>Date</TableHead>
                  <TableHead>Lead / deal</TableHead>
                  <TableHead>Team</TableHead>
                  <TableHead>Kind</TableHead>
                  <TableHead className="text-right tabular-nums">Amount</TableHead>
                  <TableHead>Status</TableHead>
                  <TableHead>Marked by</TableHead>
                  <TableHead>Role</TableHead>
                  <TableHead>Description</TableHead>
                  <TableHead>Created</TableHead>
                  <TableHead>Updated</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {items.map((row) => {
                  const isPaid = row.ledgerStatus === "paid";
                  const dealName = formatLedgerDealLabel(
                    row.dealLabel,
                    row.dealId,
                  );
                  const dateLabel =
                    row.recordedOn ??
                    (row.createdAt ? row.createdAt.slice(0, 10) : "—");
                  return (
                    <TableRow key={row.id}>
                      <TableCell className="whitespace-nowrap tabular-nums text-sm">
                        {dateLabel}
                      </TableCell>
                      <TableCell>
                        {row.dealId ? (
                          <Link
                            href={`/leads/${row.dealId}`}
                            className="font-medium text-accent hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                          >
                            {dealName}
                          </Link>
                        ) : (
                          <span className="text-[#575a62]">—</span>
                        )}
                      </TableCell>
                      <TableCell className="text-sm text-[#575a62]">
                        {row.dealTeam
                          ? formatTeamLabelForUi(row.dealTeam)
                          : "—"}
                      </TableCell>
                      <TableCell className="text-sm">
                        {formatKindLabel(row.kind)}
                      </TableCell>
                      <TableCell className="text-right font-medium tabular-nums">
                        {formatMoney(row.amount)}
                      </TableCell>
                      <TableCell>
                        <span
                          className={cn(
                            "inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium",
                            isPaid
                              ? "bg-emerald-50 text-emerald-800"
                              : "bg-amber-50 text-amber-900",
                          )}
                        >
                          {isPaid ? (
                            <CheckCircle2 className="size-3.5 shrink-0" aria-hidden />
                          ) : (
                            <Clock className="size-3.5 shrink-0" aria-hidden />
                          )}
                          {isPaid ? "Paid" : "Pending"}
                        </span>
                      </TableCell>
                      <TableCell className="max-w-[140px] truncate text-sm text-[#575a62]">
                        {row.markedByUserName ?? "—"}
                      </TableCell>
                      <TableCell className="max-w-[120px] truncate text-sm text-[#575a62]">
                        {row.markedByRoleName ?? "—"}
                      </TableCell>
                      <TableCell className="max-w-[240px] truncate text-sm text-[#575a62]">
                        {row.description ?? "—"}
                      </TableCell>
                      <TableCell className="whitespace-nowrap text-sm tabular-nums text-[#575a62]">
                        {formatTimestamp(row.createdAt)}
                      </TableCell>
                      <TableCell className="whitespace-nowrap text-sm tabular-nums text-[#575a62]">
                        {formatTimestamp(row.updatedAt)}
                      </TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
          </Table>
        )}
      </div>

      {total > 0 && (
        <div className="flex flex-wrap items-center justify-between gap-3 text-sm text-[#575a62]">
          <span>
            {total} transaction{total === 1 ? "" : "s"}
            {isFetching && !isLoading ? " · Updating…" : ""}
          </span>
          <div className="flex items-center gap-2">
            <Button
              type="button"
              variant="outline"
              size="sm"
              className="min-h-[44px]"
              disabled={page <= 1}
              onClick={() => setPage((p) => Math.max(1, p - 1))}
            >
              Previous
            </Button>
            <span className="tabular-nums">
              Page {page} of {totalPages}
            </span>
            <Button
              type="button"
              variant="outline"
              size="sm"
              className="min-h-[44px]"
              disabled={page >= totalPages}
              onClick={() => setPage((p) => Math.min(totalPages, p + 1))}
            >
              Next
            </Button>
          </div>
        </div>
      )}
    </div>
  );
}
