"use client";

import * as React from "react";
import { RefreshCw } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { cn } from "@/lib/utils";

import { DashboardWidgetBody } from "@/app/customer/_components/dashboard-charts/dashboard-widget-body";
import { ResponsiveHorizontalBarChart } from "@/app/customer/_components/dashboard-charts/responsive-horizontal-bar-chart";
import { PortfolioScopeWidgetHint } from "@/app/customer/_components/portfolio-scope-widget-hint";
import type { WidgetLayoutTier } from "@/app/customer/_lib/use-widget-container-size";
import { LAYOUT_IDS } from "@/app/customer/_lib/dashboard-layout";
import { useDashboardWidgetData } from "@/app/customer/_lib/use-dashboard-widget-data";
import { buildTopHoldingsBars } from "@/app/customer/[tenant]/reports/top-holdings/_lib/top-holdings-chart-data";
import { fetchTopHoldingsWidgetClient } from "@/app/customer/[tenant]/reports/top-holdings/_lib/top-holdings-api";
import {
  ConsolidatedIndividualDialog,
  type ConsolidatedIndividualTarget,
} from "@/app/customer/[tenant]/reports/consolidated-holdings-report/_components/consolidated-holdings-report/consolidated-individual-dialog";
import type {
  TopHoldingsAmountField,
  TopHoldingsAssetClass,
  TopHoldingsRow,
  TopHoldingsSection,
  TopHoldingsTotals,
  TopHoldingsWidgetData,
} from "@/app/customer/[tenant]/reports/top-holdings/_lib/top-holdings-types";

function amountClass(raw: number) {
  if (!Number.isFinite(raw) || Math.abs(raw) < 1e-9) return "text-foreground";
  return raw < 0 ? "text-red-600 dark:text-red-400" : "text-emerald-700 dark:text-emerald-400";
}

function formatTotalAmount(raw: number): string {
  return raw.toLocaleString("en-US", {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });
}

function canOpenIsinDrilldown(row: TopHoldingsRow): boolean {
  const isin = row.isin?.trim();
  return Boolean(isin && isin !== "—" && isin !== "--");
}

function holdingsTypeLabel(row: TopHoldingsRow): string {
  return row.product_type?.trim() || row.asset_type_title?.trim() || "—";
}

function toIndividualTarget(row: TopHoldingsRow): ConsolidatedIndividualTarget {
  return {
    isin: row.isin?.trim() ?? "",
    name: row.name?.trim() || undefined,
    assetType: row.asset_type_title?.trim() || "",
    assetClass: row.asset_class_code?.trim() || "",
  };
}

function ValueAmountsCell({
  marketValue,
  purchaseValue,
}: {
  marketValue: TopHoldingsAmountField;
  purchaseValue: TopHoldingsAmountField;
}) {
  return (
    <div className="flex flex-col items-end gap-0.5 leading-tight">
      <span className="tabular-nums font-medium" title={`Market value: ${marketValue.fmt}`}>
        <span className="text-[9px] font-normal uppercase tracking-wide text-muted-foreground">Mkt </span>
        {marketValue.fmt}
      </span>
      <span className="tabular-nums text-[10px] text-muted-foreground" title={`Purchase value: ${purchaseValue.fmt}`}>
        <span className="text-[9px] uppercase tracking-wide">Pur </span>
        {purchaseValue.fmt}
      </span>
    </div>
  );
}

function fallbackTotalsFromRows(rows: TopHoldingsRow[]): TopHoldingsTotals {
  const totalMarketValue = rows.reduce((sum, row) => sum + row.market_value_rc.raw, 0);
  const totalPurchaseValue = rows.reduce((sum, row) => sum + row.purchase_value_rc.raw, 0);
  const totalPnl = rows.reduce((sum, row) => sum + row.gain_loss_rc.raw, 0);
  const totalPct = rows.reduce((sum, row) => sum + row.portfolio_pct.raw, 0);
  return {
    market_value_rc: { raw: totalMarketValue, fmt: formatTotalAmount(totalMarketValue) },
    purchase_value_rc: { raw: totalPurchaseValue, fmt: formatTotalAmount(totalPurchaseValue) },
    gain_loss_rc: { raw: totalPnl, fmt: formatTotalAmount(totalPnl) },
    portfolio_pct: {
      raw: totalPct,
      fmt: `${totalPct.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}%`,
    },
  };
}

function HoldingsTable({
  section,
  currency,
  onIsinClick,
}: {
  section: TopHoldingsSection;
  currency: string;
  onIsinClick?: (row: TopHoldingsRow) => void;
}) {
  const rows = section.holdings;
  const others = section.others ?? null;
  const totals = section.totals ?? fallbackTotalsFromRows(rows);

  if (rows.length === 0) {
    return (
      <p className="text-muted-foreground rounded-md border border-dashed px-3 py-6 text-center text-xs">
        No holdings available.
      </p>
    );
  }

  return (
    <div className="overflow-x-auto rounded-md border [-ms-overflow-style:none] [scrollbar-width:thin] [&::-webkit-scrollbar]:h-1.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-border/80 [&::-webkit-scrollbar-track]:bg-transparent">
      <table className="w-full min-w-[640px] text-left text-[11px]">
          <thead className="sticky top-0 z-10 bg-card text-[10px] font-semibold uppercase tracking-wide text-foreground/70 backdrop-blur-sm">
            <tr>
              <th className="px-2.5 py-2">Name</th>
              <th className="px-2.5 py-2">ISIN</th>
              <th className="px-2.5 py-2">Type</th>
              <th className="px-2.5 py-2 text-right">Portfolio %</th>
              <th className="px-2.5 py-2 text-right">Value ({currency})</th>
              <th className="px-2.5 py-2 text-right">P&amp;L ({currency})</th>
            </tr>
          </thead>
          <tbody className="divide-y">
            {rows.map((row, index) => {
              const name = row.name || row.isin || "—";
              const isin = row.isin || "—";
              const isinClickable = Boolean(onIsinClick && canOpenIsinDrilldown(row));
              const pct = row.portfolio_pct as TopHoldingsAmountField;
              const marketValue = row.market_value_rc as TopHoldingsAmountField;
              const purchaseValue = row.purchase_value_rc as TopHoldingsAmountField;
              const pnl = row.gain_loss_rc as TopHoldingsAmountField;

              return (
                <tr key={`${isin}-${index}`} className="hover:bg-muted/20">
                  <td className="max-w-[180px] truncate px-2.5 py-2 font-medium" title={name}>
                    {name}
                  </td>
                  <td className="max-w-[110px] truncate px-2.5 py-2 font-mono text-[10px]" title={isin}>
                    {isinClickable ? (
                      <button
                        type="button"
                        className="text-primary hover:underline"
                        onClick={() => onIsinClick?.(row)}
                      >
                        {isin}
                      </button>
                    ) : (
                      <span className="text-muted-foreground">{isin}</span>
                    )}
                  </td>
                  <td className="max-w-[110px] truncate px-2.5 py-2 text-muted-foreground" title={holdingsTypeLabel(row)}>
                    {holdingsTypeLabel(row)}
                  </td>
                  <td className="px-2.5 py-2 text-right tabular-nums">{pct.fmt}</td>
                  <td className="px-2.5 py-2 text-right">
                    <ValueAmountsCell marketValue={marketValue} purchaseValue={purchaseValue} />
                  </td>
                  <td className={cn("px-2.5 py-2 text-right tabular-nums", amountClass(pnl.raw))}>
                    {pnl.fmt}
                  </td>
                </tr>
              );
            })}
            {others ? (
              <tr className="bg-muted/10 text-muted-foreground">
                <td className="max-w-[180px] truncate px-2.5 py-2 font-medium italic" title="Others">
                  Others
                </td>
                <td className="px-2.5 py-2 font-mono text-[10px]">—</td>
                <td className="px-2.5 py-2">—</td>
                <td className="px-2.5 py-2 text-right tabular-nums">{others.portfolio_pct.fmt}</td>
                <td className="px-2.5 py-2 text-right">
                  <ValueAmountsCell
                    marketValue={others.market_value_rc}
                    purchaseValue={others.purchase_value_rc}
                  />
                </td>
                <td className={cn("px-2.5 py-2 text-right tabular-nums", amountClass(others.gain_loss_rc.raw))}>
                  {others.gain_loss_rc.fmt}
                </td>
              </tr>
            ) : null}
          </tbody>
          <tfoot>
            <tr className="bg-muted/30 border-t font-semibold">
              <td colSpan={3} className="px-2.5 py-2">
                Total
              </td>
              <td className="px-2.5 py-2 text-right text-muted-foreground">—</td>
              <td className="px-2.5 py-2 text-right">
                <ValueAmountsCell
                  marketValue={totals.market_value_rc}
                  purchaseValue={totals.purchase_value_rc}
                />
              </td>
              <td className={cn("px-2.5 py-2 text-right tabular-nums", amountClass(totals.gain_loss_rc.raw))}>
                {totals.gain_loss_rc.fmt}
              </td>
            </tr>
          </tfoot>
        </table>
    </div>
  );
}

function hasHoldings(data: TopHoldingsWidgetData): boolean {
  if (data.all.holdings.length > 0) return true;
  return Object.values(data.by_asset_class).some((section) => section.holdings.length > 0);
}

function assetClassesWithData(data: TopHoldingsWidgetData): TopHoldingsAssetClass[] {
  return data.asset_classes.filter(
    (assetClass) => (data.by_asset_class[assetClass.code]?.holdings ?? []).length > 0,
  );
}

function CompactHoldingsList({ rows, limit = 5 }: { rows: TopHoldingsRow[]; limit?: number }) {
  return (
    <div className="divide-y">
      {rows.slice(0, limit).map((row, index) => {
        const name = row.name || row.isin || "—";
        const isin = row.isin || "—";
        return (
          <div key={`${isin}-${index}`} className="flex items-center justify-between gap-2 px-1 py-2 text-xs">
            <div className="min-w-0">
              <p className="truncate font-medium" title={name}>
                {name}
              </p>
              <p className="truncate text-[10px] text-muted-foreground">{isin}</p>
            </div>
            <span className="shrink-0 tabular-nums font-medium">{row.portfolio_pct.fmt}</span>
          </div>
        );
      })}
    </div>
  );
}

function TopHoldingsTabs({
  data,
  currency,
  onIsinClick,
}: {
  data: TopHoldingsWidgetData;
  currency: string;
  onIsinClick?: (row: TopHoldingsRow) => void;
}) {
  const visibleAssetClasses = React.useMemo(() => assetClassesWithData(data), [data]);
  const showAllTab = data.all.holdings.length > 0;
  const defaultTab = showAllTab ? "all" : (visibleAssetClasses[0]?.code ?? "all");
  const [activeTab, setActiveTab] = React.useState(defaultTab);

  React.useEffect(() => {
    setActiveTab(defaultTab);
  }, [defaultTab]);

  return (
    <Tabs value={activeTab} onValueChange={setActiveTab} className="flex flex-col gap-3">
      <div className="w-full overflow-x-auto [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
        <TabsList className="h-auto min-h-8 w-max min-w-full shrink-0 flex-nowrap justify-start">
          {showAllTab ? (
            <TabsTrigger value="all" className="shrink-0 text-xs">
              All
            </TabsTrigger>
          ) : null}
          {visibleAssetClasses.map((assetClass) => (
            <TabsTrigger key={assetClass.code} value={assetClass.code} className="shrink-0 text-xs">
              {assetClass.label}
            </TabsTrigger>
          ))}
        </TabsList>
      </div>
      {showAllTab && activeTab === "all" ? (
        <TabsContent value="all" forceMount className="mt-0">
          <HoldingsTable section={data.all} currency={currency} onIsinClick={onIsinClick} />
        </TabsContent>
      ) : null}
      {visibleAssetClasses.map((assetClass) =>
        activeTab === assetClass.code ? (
          <TabsContent key={assetClass.code} value={assetClass.code} forceMount className="mt-0">
            <HoldingsTable
              section={data.by_asset_class[assetClass.code] ?? { holdings: [] }}
              currency={currency}
              onIsinClick={onIsinClick}
            />
          </TabsContent>
        ) : null,
      )}
    </Tabs>
  );
}

function HoldingsChartPanel({
  items,
  height,
}: {
  items: ReturnType<typeof buildTopHoldingsBars>;
  height: number;
}) {
  return (
    <div className="shrink-0 rounded-lg border border-border/60 bg-card p-3">
      <p className="mb-2 text-[10px] font-semibold uppercase tracking-wide text-foreground/70">
        By market value
      </p>
      <ResponsiveHorizontalBarChart items={items} height={height} barSize={14} />
    </div>
  );
}

function TopHoldingsContent({
  data,
  currency,
  onIsinClick,
}: {
  data: TopHoldingsWidgetData;
  currency: string;
  onIsinClick?: (row: TopHoldingsRow) => void;
}) {
  const barItems = React.useMemo(() => buildTopHoldingsBars(data.all.holdings), [data.all.holdings]);

  const renderBody = (tier: WidgetLayoutTier) => {
    if (tier === "compact") {
      return <CompactHoldingsList rows={data.all.holdings} limit={3} />;
    }

    const chartHeight = Math.min(tier === "expanded" ? 150 : 220, barItems.length * 28 + 32);

    if (tier === "balanced") {
      return (
        <div className="flex flex-col gap-4">
          <HoldingsChartPanel items={barItems} height={chartHeight} />
          <CompactHoldingsList rows={data.all.holdings} />
        </div>
      );
    }

    return (
      <div className="flex flex-col gap-4">
        <HoldingsChartPanel items={barItems} height={chartHeight} />
        <TopHoldingsTabs data={data} currency={currency} onIsinClick={onIsinClick} />
      </div>
    );
  };

  return <DashboardWidgetBody className="overflow-y-auto p-4">{({ tier }) => renderBody(tier)}</DashboardWidgetBody>;
}

export function TopHoldingsWidget() {
  const [individualOpen, setIndividualOpen] = React.useState(false);
  const [individualTarget, setIndividualTarget] = React.useState<ConsolidatedIndividualTarget | null>(null);

  const handleIsinClick = React.useCallback((row: TopHoldingsRow) => {
    if (!canOpenIsinDrilldown(row)) return;
    setIndividualTarget(toIndividualTarget(row));
    setIndividualOpen(true);
  }, []);

  const fetchIndividual = React.useCallback(async (tenant: string) => {
    const result = await fetchTopHoldingsWidgetClient(tenant);
    return { data: result.data, errorMessage: result.errorMessage };
  }, []);

  const { data, loading, refreshing, error, refresh } = useDashboardWidgetData<TopHoldingsWidgetData>({
    layoutId: LAYOUT_IDS.topHoldings,
    fetchIndividual,
  });

  const currency = data?.currency ?? "USD";

  return (
    <>
      <Card className="flex h-full flex-col gap-0 overflow-hidden py-0 shadow-sm">
      <CardHeader className="flex flex-row items-start justify-between gap-3 space-y-0 border-b py-3">
        <div className="min-w-0 flex-1">
          <CardTitle className="text-base text-primary">Top Holdings</CardTitle>
          <p className="flex min-w-0 items-center gap-1.5 truncate text-[10px] text-muted-foreground">
            <span className="shrink-0">Reporting currency: {currency}</span>
            <PortfolioScopeWidgetHint inline />
          </p>
        </div>
        <Button
          variant="ghost"
          size="icon"
          className="size-8 shrink-0"
          disabled={refreshing}
          onClick={() => void refresh()}
          title="Refresh"
        >
          <RefreshCw className={cn("size-3.5", refreshing && "animate-spin")} />
          <span className="sr-only">Refresh</span>
        </Button>
      </CardHeader>

      {loading && !data ? (
        <CardContent className="flex flex-1 flex-col gap-3 p-4">
          <Skeleton className="h-8 w-48" />
          <Skeleton className="h-40 w-full" />
        </CardContent>
      ) : error ? (
        <CardContent className="flex flex-1 flex-col items-center justify-center gap-3 p-6 text-center">
          <p className="text-muted-foreground text-sm">{error}</p>
          <Button variant="outline" size="sm" onClick={() => void refresh()}>
            Try again
          </Button>
        </CardContent>
      ) : data && hasHoldings(data) ? (
        <CardContent className="relative flex min-h-0 flex-1 flex-col overflow-hidden p-0">
          {refreshing ? (
            <div
              className="absolute inset-0 z-10 flex items-center justify-center bg-background/60 backdrop-blur-[1px]"
              aria-busy="true"
              aria-live="polite"
            >
              <RefreshCw className="size-6 animate-spin text-muted-foreground" />
            </div>
          ) : null}
          <TopHoldingsContent data={data} currency={currency} onIsinClick={handleIsinClick} />
        </CardContent>
      ) : (
        <CardContent className="flex flex-1 items-center justify-center p-6 text-center">
          <p className="text-muted-foreground text-sm">No holdings found in your portfolio.</p>
        </CardContent>
      )}
    </Card>

      <ConsolidatedIndividualDialog
        open={individualOpen}
        onOpenChange={setIndividualOpen}
        target={individualTarget}
      />
    </>
  );
}
