"use client"

import * as React from "react"
import { format } from "date-fns"
import { ClipboardList, Download, FileSpreadsheet, FileText, RefreshCw, X } from "lucide-react"
import { useParams } from "next/navigation"
import { toast } from "sonner"

import { useCustomerPortalSession } from "@/app/customer/_components/customer-portal-session-context"
import { useAumCalcMode } from "@/app/customer/_lib/use-aum-calc-mode"
import { resolveCustomerTenant } from "@/app/customer/_lib/resolve-customer-tenant"
import { useReportBankModeInvalidation } from "@/app/customer/_lib/use-report-bank-mode-invalidation";
import { AsOfSnapshotBanner } from "@/app/customer/[tenant]/reports/_shared/components/as-of-snapshot-banner"
import { ReportLifecycleBadge } from "@/app/customer/[tenant]/reports/_shared/components/report-lifecycle-badge"
import { ReportLoadingPanel } from "@/app/customer/[tenant]/reports/_shared/components/report-loading-panel"
import { deriveAsOfViewState, formatYmd } from "@/app/customer/[tenant]/reports/_shared/lib/as-of-snapshot-view"
import { DatePicker } from "@/components/date-range-picker"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Switch } from "@/components/ui/switch"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { isCorporateParentPortalUser } from "@/lib/frontend-auth/report-capabilities"
import { toastApiError } from "@/lib/toast-api-error"
import { cn } from "@/lib/utils"

import { CSV_MIME, downloadCsvText } from "@/lib/csv-export";
import { downloadXlsx } from "@/lib/xlsx-export";
import { formatPlainAmount } from "@/lib/format/numbers";
import { useOverallSummaryAsOf, type AsOfSnapshotClient } from "../../overall-summary/_lib/use-overall-summary-asof"
import { fetchPibPivotAsOfStatusClient, kickoffPibPivotAsOfClient } from "../_lib/pib-pivot-asof-api"
import { CUSTOMER_ROUTE_KEYS } from "@/config/customer-route-keys";
import { sessionAllowsRouteKeys } from "@/app/customer/_lib/customer-route-guard";
import { usePibPivotReport } from "../_lib/use-pib-pivot-report"
import {
  PIB_WORKBOOK_TABS,
  isSingleClientPivot,
  type PibWorkbookTabId,
} from "../_lib/pib-pivot-data"
import { buildPibPivotCsv, buildPibPivotSheets, pibPivotExportFilename } from "../_lib/pib-pivot-export"
import { formatPibValue } from "../_lib/pib-pivot-sheet"
import { PibIndividualOverview } from "./pib-individual-overview"
import {
  PibPivotDetailDialog,
  type PibPivotDetailTarget,
} from "./pib-pivot-detail-dialog"
import { PivotSheet } from "./pib-pivot-sheet"
import { PibSummaryCalcHelp } from "./pib-summary-calc-help"

function PlaceholderSheet({ label }: { label: string }) {
  return (
    <div className="flex min-h-[20rem] flex-1 flex-col items-center justify-center gap-2 px-6 text-center">
      <FileSpreadsheet className="size-10 text-muted-foreground/40" />
      <p className="font-medium text-sm">{label}</p>
      <p className="max-w-sm text-muted-foreground text-xs">
        Empty for now — only the Pivot sheet is live.
      </p>
    </div>
  )
}

function WorkbookTabs({
  active,
  onChange,
}: {
  active: PibWorkbookTabId
  onChange: (id: PibWorkbookTabId) => void
}) {
  const readyTabs = PIB_WORKBOOK_TABS.filter((tab) => tab.ready)
  // Only Pivot is live — skip the sheet strip until more tabs ship.
  if (readyTabs.length <= 1) {
    return null
  }

  return (
    <div className="shrink-0 border-t bg-muted/30">
      <div
        className="flex items-end gap-0.5 overflow-x-auto px-2 pt-1.5 pb-0"
        role="tablist"
        aria-label="Workbook sheets"
      >
        {readyTabs.map((tab) => {
          const isActive = tab.id === active
          return (
            <button
              key={tab.id}
              type="button"
              role="tab"
              aria-selected={isActive}
              onClick={() => onChange(tab.id)}
              className={cn(
                "relative -mb-px shrink-0 truncate rounded-t-md border px-3 py-1.5 text-left text-xs transition-colors",
                isActive
                  ? "z-10 border-b-background border-border bg-background font-medium text-foreground shadow-sm"
                  : "border-transparent text-muted-foreground hover:bg-muted/80 hover:text-foreground"
              )}
              title={tab.label}
            >
              {tab.label}
            </button>
          )
        })}
      </div>
    </div>
  )
}

/** The PIB pivot reads the same per-date snapshot as the Overall Summary, via its own ACL-scoped routes. */
const PIB_AS_OF_CLIENT: AsOfSnapshotClient = {
  fetchStatus: fetchPibPivotAsOfStatusClient,
  kickoff: kickoffPibPivotAsOfClient,
}

export function PibReportView({ allowedRoutes = [] }: { allowedRoutes?: readonly string[] }) {
  const params = useParams<{ tenant?: string }>()
  const tenant =
    typeof params?.tenant === "string" && params.tenant.trim()
      ? params.tenant.trim()
      : resolveCustomerTenant()
  // Corporate parents get the pivot grid; an individual login has a single client, so it gets
  // the calculation + holdings overview instead.
  const { user } = useCustomerPortalSession()
  const isIndividualLogin = !isCorporateParentPortalUser(user)
  const [refreshKey, setRefreshKey] = React.useState(0)
  // The total follows the AUM mode (Gross / Net) like the Overall Summary, so a change in the header
  // badge must re-read the report. The first value is the initial load, not a change.
  const { mode: headerAumMode } = useAumCalcMode()
  const skipFirstAumRefresh = React.useRef(true)
  React.useEffect(() => {
    if (skipFirstAumRefresh.current) {
      skipFirstAumRefresh.current = false
      return
    }
    setRefreshKey((key) => key + 1)
  }, [headerAumMode])
  // Historical "as of" view: a past date shows holdings, prices and FX as they stood then.
  // Today / a future date is the same as live, so it is treated as no date.
  const [asOfDate, setAsOfDate] = React.useState("")
  // "Bank prices": each holding valued at its own bank's market price / FX rate (where the bank
  // has one) instead of the price master. Works with the as-of date too.
  const [useBankPrices, setUseBankPrices] = React.useState(false)
  const todayYmd = format(new Date(), "yyyy-MM-dd")
  const effectiveAsOf = asOfDate && asOfDate < todayYmd ? asOfDate : ""
  const reportQueryString = React.useMemo(() => {
    const qs = new URLSearchParams()
    if (effectiveAsOf) qs.set("as_of_date", effectiveAsOf)
    if (useBankPrices) qs.set("bank_prices", "1")
    return qs.toString()
  }, [effectiveAsOf, useBankPrices])

  const handleAsOfBuilt = React.useCallback(() => {
    setRefreshKey((key) => key + 1)
    toast.success("Snapshot ready")
  }, [])
  const handleAsOfFailed = React.useCallback((error: string) => {
    toast.error(error)
  }, [])
  const {
    state: asOfState,
    isBuilding: isBuildingAsOf,
    errorMessage: asOfErrorMessage,
    rebuild: rebuildAsOf,
  } = useOverallSummaryAsOf({
    asOf: effectiveAsOf,
    onBuilt: handleAsOfBuilt,
    onFailed: handleAsOfFailed,
    client: PIB_AS_OF_CLIENT,
  })
  const asOfView = deriveAsOfViewState(effectiveAsOf, asOfState)
  const { snapshotReady: asOfSnapshotReady, waiting: asOfWaiting, failed: asOfFailed } = asOfView

  const { report, isLoading: reportLoading, errorMessage } = usePibPivotReport(
    tenant,
    reportQueryString,
    refreshKey,
    asOfSnapshotReady
  )
  const isLoading = reportLoading || asOfWaiting

  // The pivot grid merged into the page-level "PIB Report" grant this page is already gated
  // on (see report-page-guard.tsx) — no separate checkbox/key of its own. Cell drill-down
  // kept its own Portal Access checkbox ("PIB Pivot Detail API"), so it's still gated here.
  const canViewDetail = React.useMemo(
    () => sessionAllowsRouteKeys(allowedRoutes, [CUSTOMER_ROUTE_KEYS.pibPivotDetail]),
    [allowedRoutes],
  )
  const handleRebuildSnapshot = async () => {
    try {
      await rebuildAsOf()
      toast.message("Snapshot rebuild queued", {
        description: `Rebuilding the summary as of ${formatYmd(effectiveAsOf)} in the background.`,
      })
    } catch (error) {
      toastApiError(error, "Could not start snapshot rebuild")
    }
  }
  const [activeTab, setActiveTab] = React.useState<PibWorkbookTabId>("pivot")
  const [detailTarget, setDetailTarget] = React.useState<PibPivotDetailTarget | null>(null)
  const [filterStats, setFilterStats] = React.useState({
    visible: 0,
    total: 0,
    active: false,
  })

  useReportBankModeInvalidation(() => {
    setRefreshKey((key) => key + 1)
  })

  const onFilterStatsChange = React.useCallback(
    (stats: { visible: number; total: number; active: boolean }) => {
      setFilterStats(stats)
    },
    []
  )
  const activeMeta = PIB_WORKBOOK_TABS.find((t) => t.id === activeTab)

  const title = report?.title ?? "PIB Advisory — Pivot"
  const periodLabel = asOfWaiting
    ? `Building snapshot as of ${formatYmd(effectiveAsOf)}…`
    : (report?.periodLabel ?? "Loading…")
  const currencyNote = report?.currencyNote ?? ""
  const dataSource = report?.dataSource ?? "live"
  const totalAssetsAdvisedUsd = report?.totalAssetsAdvisedUsd ?? 0
  const assignedAssetsUsd = report?.assignedAssetsUsd ?? 0
  const inferredAssetsUsd = report?.inferredAssetsUsd ?? 0
  const potentialAssetsUsd = report?.potentialAssetsUsd ?? 0
  const loanLiabilityUsd = report?.loanLiabilityUsd ?? 0
  const reportingCurrency = report?.defaultCurrencyCode ?? "USD"
  const aumMode = report?.aumMode ?? "gross"
  // While a first-time snapshot builds, never show rows left over from another date.
  const pivotRows = asOfWaiting ? [] : (report?.pivotRows ?? [])
  const noSnapshot = dataSource === "missing" && !asOfWaiting
  const rowCountLabel = noSnapshot
    ? "No snapshot"
    : filterStats.active
      ? `${formatPlainAmount(filterStats.visible)} of ${formatPlainAmount(filterStats.total)} pivot rows`
      : `${formatPlainAmount(pivotRows.length)} pivot row${pivotRows.length === 1 ? "" : "s"}`
  // An individual login has one client; if the rows say otherwise keep the pivot grid.
  const isIndividual = isIndividualLogin && isSingleClientPivot(pivotRows)
  const sourceBadge =
    isLoading ? "Loading" : dataSource === "snapshot" ? "Snapshot" : dataSource === "missing" ? "No snapshot" : "Live"
  // How much of the book the bank actually priced; holdings without bank data keep master prices.
  // No master fallback: holdings whose bank sent no price / FX rate are left out of the totals.
  const bankMissing = report?.bankMissingHoldings ?? 0
  const bankPriceNote =
    useBankPrices && report?.priceSource === "bank" && !isLoading
      ? {
          found: bankMissing === 0,
          text:
            `Bank price on ${formatPlainAmount(report.bankPricedHoldings ?? 0)} · bank FX on ${formatPlainAmount(report.bankFxHoldings ?? 0)}` +
            (bankMissing > 0
              ? ` · ${formatPlainAmount(bankMissing)} holding${bankMissing === 1 ? "" : "s"} not counted (no bank data)`
              : " holdings"),
        }
      : null
  const canDownload = report != null && pivotRows.length > 0 && !isLoading
  const handleDownload = (format: "xlsx" | "csv") => {
    if (!report) return
    const filename = pibPivotExportFilename(effectiveAsOf, format)
    if (format === "xlsx") {
      downloadXlsx({ filename, sheets: buildPibPivotSheets(report) })
    } else {
      downloadCsvText({
        filename,
        // BOM so Excel reads the file as UTF-8 (em dashes, non-Latin client names).
        text: `﻿${buildPibPivotCsv(report)}`,
        mimeType: CSV_MIME,
      })
    }
    toast.success(format === "xlsx" ? "PIB report Excel downloaded." : "PIB report CSV downloaded.")
  }

  const emptyState = (
    <div className="flex min-h-0 flex-1 flex-col items-center justify-center gap-2 px-6 py-16 text-center">
      <FileSpreadsheet className="size-10 text-muted-foreground/40" />
      <p className="font-medium text-sm">
        {asOfFailed ? "Snapshot could not be built" : noSnapshot ? "No snapshot for this date" : "No pivot data"}
      </p>
      <p className="max-w-sm text-muted-foreground text-xs">
        {asOfFailed ? (
          <>Use Rebuild snapshot to try again, or clear the date to view live holdings.</>
        ) : noSnapshot ? (
          <>
            The snapshot for{" "}
            <span className="font-medium text-foreground">{formatYmd(effectiveAsOf)}</span>{" "}
            is not built yet. Clear the date to view live holdings.
          </>
        ) : effectiveAsOf ? (
          <>No holdings on {formatYmd(effectiveAsOf)}.</>
        ) : (
          <>
            Assign PIB classes in ISIN Asset Master and ensure overall summary rows are
            stamped with <code className="font-mono">pib_class</code>.
          </>
        )}
      </p>
    </div>
  )

  return (
    <div className="flex h-[calc(100dvh-8rem)] min-w-0 w-full flex-col gap-3 overflow-hidden">
      <header className="flex shrink-0 flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
        <div className="space-y-1">
          <div className="flex flex-wrap items-center gap-2">
            <ClipboardList className="size-5 text-emerald-700 dark:text-emerald-400" />
            <h1 className="font-semibold text-xl tracking-tight">{title}</h1>
            <Badge variant="secondary">{sourceBadge}</Badge>
          </div>
          <p className="text-muted-foreground text-sm">
            {periodLabel}
            {currencyNote ? ` · ${currencyNote}` : ""}
          </p>
          {errorMessage ? <p className="text-destructive text-sm">{errorMessage}</p> : null}
          {asOfErrorMessage ? <p className="text-destructive text-sm">{asOfErrorMessage}</p> : null}
          {asOfFailed && asOfState?.error ? (
            <p className="text-destructive text-sm">Snapshot build failed: {asOfState.error}</p>
          ) : null}
        </div>
        <div className="flex shrink-0 flex-wrap items-center gap-2">
          <div className="flex items-center gap-1.5">
            <DatePicker
              value={asOfDate}
              placeholder="As of date (live)"
              align="end"
              className="h-9 w-[10.5rem]"
              onChange={(value) => setAsOfDate(value)}
            />
            {asOfDate ? (
              <Button
                type="button"
                variant="ghost"
                size="icon"
                className="size-9 shrink-0"
                aria-label="Clear as-of date (use live data)"
                onClick={() => setAsOfDate("")}
              >
                <X className="size-4" />
              </Button>
            ) : null}
          </div>
          {effectiveAsOf ? (
            <Button
              type="button"
              variant="outline"
              size="sm"
              className="h-9 shrink-0 gap-1.5"
              disabled={isBuildingAsOf}
              onClick={() => void handleRebuildSnapshot()}
            >
              <RefreshCw className={cn("size-3.5", isBuildingAsOf && "animate-spin")} />
              {isBuildingAsOf ? "Rebuilding…" : "Rebuild snapshot"}
            </Button>
          ) : null}
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button
                type="button"
                variant="outline"
                size="sm"
                className="h-9 shrink-0 gap-1.5"
                disabled={!canDownload}
                title="Download every pivot row with all columns and the summary totals"
              >
                <Download className="size-3.5" />
                Download
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end" className="min-w-[11rem]">
              <DropdownMenuItem className="gap-2 whitespace-nowrap" onClick={() => handleDownload("xlsx")}>
                <FileSpreadsheet className="size-4 text-emerald-700 dark:text-emerald-400" />
                Excel (.xlsx)
              </DropdownMenuItem>
              <DropdownMenuItem className="gap-2 whitespace-nowrap" onClick={() => handleDownload("csv")}>
                <FileText className="size-4 text-muted-foreground" />
                CSV (.csv)
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
          <Button
            type="button"
            variant="outline"
            size="icon"
            className="size-9 shrink-0"
            aria-label="Refresh report"
            onClick={() => setRefreshKey((key) => key + 1)}
          >
            <RefreshCw className={cn("size-4", isLoading && "animate-spin")} />
          </Button>
        </div>
      </header>

      {effectiveAsOf ? (
        <AsOfSnapshotBanner
          className="shrink-0"
          asOf={effectiveAsOf}
          view={asOfView}
          buildingAsOf={asOfState?.buildingAsOf}
          onBackToLive={() => setAsOfDate("")}
        />
      ) : null}

      {isIndividual ? (
        <ReportLoadingPanel
          loading={isLoading}
          label="Loading PIB report…"
          minHeightClassName="min-h-0"
          className={cn("flex min-h-0 flex-1 flex-col overflow-hidden", isLoading && "pointer-events-none")}
        >
          {pivotRows.length === 0 && !isLoading ? (
            emptyState
          ) : (
            <PibIndividualOverview
              rows={pivotRows}
              currency={reportingCurrency}
              totalAssets={totalAssetsAdvisedUsd}
              assigned={assignedAssetsUsd}
              inferred={inferredAssetsUsd}
              potential={potentialAssetsUsd}
              loanLiability={loanLiabilityUsd}
              aumMode={aumMode}
              periodLabel={periodLabel}
              onOpenDetail={canViewDetail ? setDetailTarget : undefined}
            />
          )}
        </ReportLoadingPanel>
      ) : (
      <>
      <div className="overflow-hidden rounded-xl border border-border/80 bg-card shadow-sm">
        <div className="flex flex-wrap items-baseline gap-x-2.5 gap-y-1 px-4 py-2.5 sm:px-5">
          <span className="font-semibold text-[11px] text-emerald-700 uppercase tracking-wider dark:text-emerald-400">
            B410_7001T — {aumMode === "net" ? "Net assets advised" : "Total assets advised"}
          </span>
          <Badge
            variant="outline"
            className="shrink-0 font-normal text-[10px]"
            title="Follows the AUM setting, like the Overall Summary total"
          >
            {aumMode === "net" ? "Net AUM" : "Gross AUM"}
          </Badge>
          <span className="inline-flex items-center gap-1.5 font-semibold text-lg tabular-nums tracking-tight text-emerald-700 dark:text-emerald-400">
            <span className="font-bold text-sm text-foreground">{reportingCurrency}</span>
            {formatPibValue(totalAssetsAdvisedUsd)}
            <PibSummaryCalcHelp
              currency={reportingCurrency}
              totalAssets={totalAssetsAdvisedUsd}
              assigned={assignedAssetsUsd}
              inferred={inferredAssetsUsd}
              potential={potentialAssetsUsd}
              loanLiability={loanLiabilityUsd}
              aumMode={aumMode}
            />
          </span>
          <span className="ml-auto flex items-center gap-3 self-center">
          {bankPriceNote ? (
            <span
              className={cn(
                "text-[11px]",
                bankPriceNote.found ? "text-muted-foreground" : "text-amber-700 dark:text-amber-400"
              )}
            >
              {bankPriceNote.text}
            </span>
          ) : null}
          <label
            htmlFor="pib-bank-prices"
            title="Fetch market data according to bank"
            className="flex cursor-pointer select-none items-center gap-2 font-medium text-muted-foreground text-xs transition-colors has-data-checked:text-emerald-700 dark:has-data-checked:text-emerald-400"
          >
            Bank prices
            <Switch
              id="pib-bank-prices"
              checked={useBankPrices}
              onCheckedChange={setUseBankPrices}
              className="data-checked:bg-emerald-600 dark:data-checked:bg-emerald-500"
            />
          </label>
          </span>
        </div>
      </div>

      <div className="flex min-h-0 flex-1 flex-col overflow-hidden rounded-xl border bg-background shadow-sm">
        <div className="flex shrink-0 items-center justify-between gap-2 border-b bg-muted/30 px-3 py-1.5">
          <div className="flex items-center gap-2 text-xs">
            <FileSpreadsheet className="size-3.5 text-emerald-700 dark:text-emerald-400" />
            <span className="font-medium">{activeMeta?.label ?? activeTab}</span>
          </div>
          <span className="flex flex-wrap items-center justify-end gap-x-2 gap-y-0.5 text-[10px] text-muted-foreground">
            <span>
              {rowCountLabel}
              {activeTab === "pivot" ? " · click an amount to view holdings" : ""}
            </span>
            {activeTab === "pivot" ? (
              <>
                <span className="inline-flex items-center gap-1" title="Holding has no ISIN PIB assignment — bucket inferred from AC">
                  <span className="inline-block size-1.5 rounded-full bg-amber-500" aria-hidden />
                  inferred PIB
                </span>
                <span
                  className="inline-flex items-center"
                  title="Structured Products Potential notes — shown on drill, not included in PIB totals"
                >
                  <ReportLifecycleBadge kind="potential" className="pointer-events-none" />
                </span>
                {useBankPrices ? (
                  <span
                    className="inline-flex items-center gap-1"
                    title="Holding has no bank market price or FX — not counted in Bank prices totals"
                  >
                    <span
                      className="inline-flex h-5 items-center rounded-md border border-rose-500/30 bg-rose-500/10 px-1.5 text-[10px] font-semibold uppercase tracking-wide text-rose-800 dark:text-rose-200"
                      aria-hidden
                    >
                      No MP/FX
                    </span>
                  </span>
                ) : null}
                <span
                  className="inline-flex items-center gap-1"
                  title="Negative market value (accounting style)"
                >
                  <span className="font-medium tabular-nums text-red-600 dark:text-red-400" aria-hidden>
                    (0.00)
                  </span>
                  negative value
                </span>
              </>
            ) : null}
          </span>
        </div>

        <div className="flex min-h-0 flex-1 flex-col overflow-hidden">
          {activeTab === "pivot" ? (
            <ReportLoadingPanel
              loading={isLoading}
              label="Loading PIB pivot…"
              minHeightClassName="min-h-0"
              className={cn("flex min-h-0 flex-1 flex-col overflow-hidden", isLoading && "pointer-events-none")}
            >
              {pivotRows.length === 0 && !isLoading ? (
                emptyState
              ) : (
                <PivotSheet
                  rows={pivotRows}
                  onCellClick={canViewDetail ? setDetailTarget : undefined}
                  onFilterStatsChange={onFilterStatsChange}
                />
              )}
            </ReportLoadingPanel>
          ) : (
            <div className="flex min-h-0 flex-1 flex-col overflow-hidden">
              <PlaceholderSheet label={activeMeta?.label ?? activeTab} />
            </div>
          )}
        </div>

        <WorkbookTabs active={activeTab} onChange={setActiveTab} />
      </div>
      </>
      )}

      <PibPivotDetailDialog
        target={detailTarget}
        asOfDate={effectiveAsOf}
        bankPrices={useBankPrices}
        open={detailTarget != null}
        onOpenChange={(open) => {
          if (!open) setDetailTarget(null)
        }}
      />
    </div>
  )
}
