"use client";

import * as React from "react";
import { Coins, Download, Landmark, Layers, PiggyBank, RefreshCw, Scale, TrendingDown, Wallet, X, Banknote } from "lucide-react";
import { toast } from "sonner";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { cn } from "@/lib/utils";
import {
  CurrencyBadge,
  StatItem,
} from "@/app/customer/[tenant]/reports/_shared/components/report-view-primitives";
import { formatAmount, formatQuantity } from "@/lib/format/numbers";

import { useImpersonationScopeRefresh } from "@/app/customer/_lib/admin/use-impersonation-scope-refresh";
import { ReportLoadingPanel } from "@/app/customer/[tenant]/reports/_shared/components/report-loading-panel";
import { CashBalanceFiltersDialog } from "../../cash-balance-report/_components/cash-balance-report/cash-balance-filters-dialog";
import {
  type CashBalanceFilters,
  type CashBalanceSortOrder,
  applyCashBalanceFilters,
  buildDefaultCashBalanceFilters,
  hasActiveCashBalanceFilters,
  isFullSelection,
} from "../../cash-balance-report/_components/cash-balance-report/schema";
import {
  LiquidityCurrencySheet,
  type LiquidityCurrencyTarget,
} from "./liquidity-currency-sheet";
import type {
  LiquidityAumMode,
  LiquidityComponent,
  LiquidityCurrencyTotal,
  LiquidityDetailRow,
} from "../_lib/liquidity-schema";
import { useLiquidityReportList } from "../_lib/use-liquidity-report-list";

function isNonZeroAmount(amount: number) {
  return Math.abs(amount) > 1e-9;
}

function hasNonZeroBalance(row: Pick<LiquidityComponent, "cash" | "call" | "fixed" | "leverage" | "net">) {
  return (
    isNonZeroAmount(row.cash) ||
    isNonZeroAmount(row.call) ||
    isNonZeroAmount(row.fixed) ||
    isNonZeroAmount(row.leverage) ||
    isNonZeroAmount(row.net)
  );
}

type CurrencyBalanceTotal = {
  currency: string;
  cash: number;
  call: number;
  fixed: number;
  leverage: number;
  net: number;
  count: number;
};

function aggregateByCurrency(
  rows: LiquidityComponent[],
  aumMode: LiquidityAumMode | null,
  currencyTotalsGross: LiquidityCurrencyTotal[],
  sortOrder: CashBalanceSortOrder,
): CurrencyBalanceTotal[] {
  const map = new Map<string, CurrencyBalanceTotal>();
  const grossByCurrency = new Map(
    currencyTotalsGross.map((row) => [row.currency, row.total] as const),
  );

  for (const row of rows) {
    if (!hasNonZeroBalance(row)) continue;
    const existing = map.get(row.currency) ?? {
      currency: row.currency,
      cash: 0,
      call: 0,
      fixed: 0,
      leverage: 0,
      net: 0,
      count: 0,
    };
    map.set(row.currency, {
      currency: row.currency,
      cash: existing.cash + row.cash,
      call: existing.call + row.call,
      fixed: existing.fixed + row.fixed,
      leverage: existing.leverage + row.leverage,
      net: existing.net + row.net,
      count: existing.count + 1,
    });
  }

  const items = [...map.values()]
    .map((item) => {
      if (aumMode === "gross") {
        const gross = grossByCurrency.get(item.currency);
        if (gross != null) {
          return { ...item, net: gross };
        }
        return {
          ...item,
          net: (item.cash >= 0 ? item.cash : 0) + item.call + item.fixed,
        };
      }
      return item;
    })
    .filter((item) => hasNonZeroBalance(item));

  if (sortOrder) {
    items.sort((a, b) => (sortOrder === "asc" ? a.net - b.net : b.net - a.net));
  } else {
    items.sort((a, b) => a.currency.localeCompare(b.currency));
  }

  return items;
}

export function LiquidityReportView() {
  const [filters, setFilters] = React.useState<CashBalanceFilters>(buildDefaultCashBalanceFilters());
  const [sortOrder, setSortOrder] = React.useState<CashBalanceSortOrder>(null);
  const [refreshKey, setRefreshKey] = React.useState(0);
  const [currencyTarget, setCurrencyTarget] = React.useState<LiquidityCurrencyTarget | null>(null);
  const [currencySheetOpen, setCurrencySheetOpen] = React.useState(false);
  const initializedFiltersRef = React.useRef(false);

  const refreshForPortfolioScope = React.useCallback(() => {
    initializedFiltersRef.current = false;
    setFilters(buildDefaultCashBalanceFilters());
    setRefreshKey((value) => value + 1);
  }, []);
  useImpersonationScopeRefresh(refreshForPortfolioScope);

  const {
    components,
    detailRows,
    currencies,
    currencyTotalsGross,
    aumMode,
    excludedCash,
    excludedLeverage,
    bankOptions,
    currencyOptions,
    isLoading,
    errorMessage,
  } = useLiquidityReportList(refreshKey);

  React.useEffect(() => {
    if (!initializedFiltersRef.current && bankOptions.length > 0) {
      setFilters({ banks: [...bankOptions], currencies: [...currencyOptions] });
      initializedFiltersRef.current = true;
    }
  }, [bankOptions, currencyOptions]);

  const filteredComponents = React.useMemo(
    () => applyCashBalanceFilters(components, filters, bankOptions, currencyOptions),
    [components, filters, bankOptions, currencyOptions],
  );

  const filteredDetailRows = React.useMemo(() => {
    const bankActive = filters.banks.length > 0 && !isFullSelection(filters.banks, bankOptions);
    const currencyActive =
      filters.currencies.length > 0 && !isFullSelection(filters.currencies, currencyOptions);

    return detailRows.filter((row: LiquidityDetailRow) => {
      if (bankActive && !filters.banks.includes(row.bank)) return false;
      if (currencyActive && !filters.currencies.includes(row.currency)) return false;
      return true;
    });
  }, [detailRows, filters, bankOptions, currencyOptions]);

  const currencyTotals = React.useMemo(
    () => aggregateByCurrency(filteredComponents, aumMode, currencyTotalsGross, sortOrder),
    [filteredComponents, aumMode, currencyTotalsGross, sortOrder],
  );

  const uniqueBanks = React.useMemo(() => {
    const banks = new Set<string>();
    for (const row of filteredComponents) {
      if (hasNonZeroBalance(row)) banks.add(row.bank);
    }
    return banks.size;
  }, [filteredComponents]);

  const uniqueCurrencies = currencyTotals.length;
  const nonZeroPositions = filteredComponents.filter((row) => hasNonZeroBalance(row)).length;
  const netMovement = currencyTotals.reduce((sum, item) => sum + item.net, 0);
  const hasActiveFilters = hasActiveCashBalanceFilters(filters, bankOptions, currencyOptions);

  const resetFilters = () => {
    setFilters({ banks: [...bankOptions], currencies: [...currencyOptions] });
    setSortOrder(null);
  };

  const handleApplyFilters = (nextFilters: CashBalanceFilters, nextSort: CashBalanceSortOrder) => {
    setFilters(nextFilters);
    setSortOrder(nextSort);
    toast.success("Liquidity report generated", {
      description: "Filters applied to liquidity report.",
    });
  };

  const openCurrencySheet = (item: CurrencyBalanceTotal) => {
    const currencyName =
      currencies.find((c) => c.code === item.currency)?.name?.trim() || undefined;
    setCurrencyTarget({
      currency: item.currency,
      currencyName,
      net: item.net,
      cash: item.cash,
      call: item.call,
      fixed: item.fixed,
      leverage: item.leverage,
    });
    setCurrencySheetOpen(true);
  };

  return (
    <div className="flex min-w-0 flex-col gap-5">
      <div className="flex flex-col gap-3 border-b pb-4 sm:flex-row sm:items-center sm:justify-between">
        <div className="min-w-0">
          <div className="flex items-center gap-2.5">
            <div className="flex size-8 items-center justify-center rounded-lg border border-blue-700/15 bg-blue-700/[0.06] text-blue-700 dark:border-blue-300/20 dark:bg-blue-300/10 dark:text-blue-300">
              <Scale className="size-4" />
            </div>
            <div>
              <h1 className="font-semibold text-2xl leading-none tracking-tight">Liquidity Report</h1>
              <p className="mt-1.5 text-muted-foreground text-sm">
                {isLoading ? "Loading…" : `${uniqueBanks} banks · ${uniqueCurrencies} currencies`}
                {hasActiveFilters ? " · filtered" : ""}
                {sortOrder ? ` · sorted ${sortOrder.toUpperCase()}` : ""}
                {aumMode ? ` · AUM ${aumMode}` : ""}
                {" · zeros hidden"}
              </p>
            </div>
          </div>
          {errorMessage ? <p className="mt-1.5 text-destructive text-sm">{errorMessage}</p> : null}
        </div>

        <div className="flex shrink-0 items-center justify-end gap-2">
          <CashBalanceFiltersDialog
            filters={filters}
            sortOrder={sortOrder}
            bankOptions={bankOptions}
            currencyOptions={currencyOptions}
            onApply={handleApplyFilters}
          />
          <Button
            variant="outline"
            size="icon"
            className="size-9 shrink-0"
            onClick={() =>
              toast.message("Download started", {
                description: "Liquidity export will be available when connected to API.",
              })
            }
          >
            <Download className="size-4" />
            <span className="sr-only">Download report</span>
          </Button>
          <Button
            variant="outline"
            size="icon"
            className="size-9 shrink-0"
            disabled={isLoading}
            onClick={() => setRefreshKey((value) => value + 1)}
          >
            <RefreshCw className={cn("size-4", isLoading && "animate-spin")} />
            <span className="sr-only">Refresh</span>
          </Button>
        </div>
      </div>

      {hasActiveFilters ? (
        <div className="flex flex-wrap items-center gap-2">
          <span className="font-medium text-muted-foreground text-xs uppercase tracking-wider">Active filters</span>
          {!isFullSelection(filters.banks, bankOptions) ? (
            <Badge variant="secondary" className="gap-1 pr-1">
              Banks: {filters.banks.length} selected
              <button
                type="button"
                className="rounded-full p-0.5 hover:bg-muted"
                onClick={() => setFilters((p) => ({ ...p, banks: [...bankOptions] }))}
              >
                <X className="size-3" />
              </button>
            </Badge>
          ) : null}
          {!isFullSelection(filters.currencies, currencyOptions) ? (
            <Badge variant="secondary" className="gap-1 pr-1">
              Currencies: {filters.currencies.length} selected
              <button
                type="button"
                className="rounded-full p-0.5 hover:bg-muted"
                onClick={() => setFilters((p) => ({ ...p, currencies: [...currencyOptions] }))}
              >
                <X className="size-3" />
              </button>
            </Badge>
          ) : null}
          <button
            type="button"
            className="text-muted-foreground text-xs underline-offset-2 hover:text-foreground hover:underline"
            onClick={resetFilters}
          >
            Clear all
          </button>
        </div>
      ) : null}

      <div className="overflow-hidden rounded-lg border border-border/80 bg-card shadow-xs">
        <div className="grid grid-cols-1 divide-y divide-border sm:grid-cols-2 sm:divide-y-0 lg:grid-cols-4 lg:divide-x">
          <StatItem
            icon={<Landmark className="size-4" />}
            label="Banks"
            value={uniqueBanks}
            hint="With non-zero balances"
            accentClassName="border-violet-700/15 bg-violet-700/[0.06] text-violet-700 dark:border-violet-300/20 dark:bg-violet-300/10 dark:text-violet-300"
          />
          <StatItem
            icon={<Coins className="size-4" />}
            label="Currencies"
            value={uniqueCurrencies}
            hint="Non-zero totals"
            accentClassName="border-amber-700/15 bg-amber-700/[0.06] text-amber-800 dark:border-amber-300/20 dark:bg-amber-300/10 dark:text-amber-300"
          />
          <StatItem
            icon={<Layers className="size-4" />}
            label="Positions"
            value={nonZeroPositions}
            hint="Non-zero balances"
            accentClassName="border-teal-700/15 bg-teal-700/[0.06] text-teal-700 dark:border-teal-300/20 dark:bg-teal-300/10 dark:text-teal-300"
          />
          <StatItem
            icon={<Scale className="size-4" />}
            label={aumMode === "gross" ? "Gross movement" : "Net movement"}
            value={netMovement >= 0 ? `+${formatQuantity(netMovement)}` : formatQuantity(netMovement)}
            hint={
              aumMode === "gross"
                ? `AUM gross · excl. cash ${formatQuantity(excludedCash)} · excl. lev ${formatQuantity(excludedLeverage)}`
                : "Sum of net across currencies"
            }
            accentClassName="border-blue-700/15 bg-blue-700/[0.06] text-blue-700 dark:border-blue-300/20 dark:bg-blue-300/10 dark:text-blue-300"
          />
        </div>
      </div>

      <ReportLoadingPanel
        loading={isLoading}
        label="Loading liquidity report…"
        className={cn(isLoading && "pointer-events-none")}
      >
        {currencyTotals.length === 0 && !isLoading ? (
          <Card className="border-dashed py-0">
            <CardContent className="flex flex-col items-center justify-center gap-2 py-10 text-center">
              <Scale className="size-8 text-blue-700/50 dark:text-blue-300/50" />
              <p className="font-medium text-sm">No non-zero balance records found</p>
              <p className="max-w-sm text-muted-foreground text-xs">
                Open filters, adjust selections, and click Generate Report.
              </p>
              <CashBalanceFiltersDialog
                filters={filters}
                sortOrder={sortOrder}
                bankOptions={bankOptions}
                currencyOptions={currencyOptions}
                onApply={handleApplyFilters}
              />
            </CardContent>
          </Card>
        ) : (
          <Card className="gap-0 overflow-hidden border-border/80 bg-card py-0 shadow-xs">
            <CardHeader className="flex flex-row items-center justify-between gap-2 border-b bg-muted/30 px-4 py-3.5">
              <div>
                <CardTitle className="text-base">
                  {aumMode === "gross" ? "Gross balance by currency" : "Net balance by currency"}
                </CardTitle>
                <CardDescription className="text-xs">
                  {uniqueBanks} banks · zero balances hidden
                  {hasActiveFilters ? " · filtered" : ""}
                  {" · click a currency for customer details"}
                </CardDescription>
              </div>
              <Badge variant="secondary" className="h-6 border-primary/15 bg-primary/10 text-primary text-xs">
                {currencyTotals.length} currencies
              </Badge>
            </CardHeader>
            <CardContent className="p-3.5">
              {currencyTotals.length === 0 ? (
                <div className="h-40" aria-hidden />
              ) : (
                <div className="grid grid-cols-1 gap-2.5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
                  {currencyTotals.map((item) => (
                    <button
                      key={item.currency}
                      type="button"
                      onClick={() => openCurrencySheet(item)}
                      className="rounded-lg border border-border/80 bg-background px-3 py-2.5 text-left transition-colors hover:border-primary/30 hover:bg-primary/[0.03] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                    >
                      <div className="flex items-center justify-between gap-1">
                        <CurrencyBadge currency={item.currency} />
                        <span className="text-muted-foreground text-xs">{item.count} banks</span>
                      </div>
                      <p className="mt-2 font-semibold text-base text-violet-700 tabular-nums leading-tight dark:text-violet-400">
                        {formatAmount(item.net)}
                      </p>
                      <p className="mt-0.5 text-[10px] font-medium uppercase tracking-wider text-muted-foreground">
                        {aumMode === "gross" ? "Gross total" : "Net total"}
                      </p>
                      <div className="mt-2.5 grid grid-cols-1 gap-1.5">
                        <div className="flex items-center justify-between gap-2 rounded-md border border-teal-700/10 bg-teal-700/[0.04] px-2 py-1.5 dark:border-teal-300/15 dark:bg-teal-300/5">
                          <p className="flex shrink-0 items-center gap-1 text-[10px] font-medium text-teal-800 dark:text-teal-300">
                            <Wallet className="size-2.5 shrink-0" />
                            Cash
                          </p>
                          <p className="text-right text-[11px] font-medium tabular-nums text-foreground">
                            {formatAmount(item.cash)}
                          </p>
                        </div>
                        <div className="flex items-center justify-between gap-2 rounded-md border border-blue-700/10 bg-blue-700/[0.04] px-2 py-1.5 dark:border-blue-300/15 dark:bg-blue-300/5">
                          <p className="flex shrink-0 items-center gap-1 text-[10px] font-medium text-blue-800 dark:text-blue-300">
                            <Banknote className="size-2.5 shrink-0" />
                            Call
                          </p>
                          <p className="text-right text-[11px] font-medium tabular-nums text-foreground">
                            {formatAmount(item.call)}
                          </p>
                        </div>
                        <div className="flex items-center justify-between gap-2 rounded-md border border-emerald-700/10 bg-emerald-700/[0.04] px-2 py-1.5 dark:border-emerald-300/15 dark:bg-emerald-300/5">
                          <p className="flex shrink-0 items-center gap-1 text-[10px] font-medium text-emerald-800 dark:text-emerald-300">
                            <PiggyBank className="size-2.5 shrink-0" />
                            Fixed
                          </p>
                          <p className="text-right text-[11px] font-medium tabular-nums text-foreground">
                            {formatAmount(item.fixed)}
                          </p>
                        </div>
                        <div className="flex items-center justify-between gap-2 rounded-md border border-rose-700/10 bg-rose-700/[0.04] px-2 py-1.5 dark:border-rose-300/15 dark:bg-rose-300/5">
                          <p className="flex shrink-0 items-center gap-1 text-[10px] font-medium text-rose-800 dark:text-rose-300">
                            <TrendingDown className="size-2.5 shrink-0" />
                            Leverage
                          </p>
                          <p className="text-right text-[11px] font-medium tabular-nums text-foreground">
                            {formatAmount(item.leverage)}
                          </p>
                        </div>
                      </div>
                    </button>
                  ))}
                </div>
              )}
            </CardContent>
          </Card>
        )}
      </ReportLoadingPanel>

      <LiquidityCurrencySheet
        open={currencySheetOpen}
        onOpenChange={setCurrencySheetOpen}
        target={currencyTarget}
        detailRows={filteredDetailRows}
        aumMode={aumMode}
        eyebrow="Liquidity"
      />
    </div>
  );
}
