"use client"

import * as React from "react"
import { ArrowRight, Landmark } from "lucide-react"

import { EM_DASH, formatAccounting } from "@/lib/format/numbers"
import { cn } from "@/lib/utils"
import { ReportLifecycleBadge } from "@/app/customer/[tenant]/reports/_shared/components/report-lifecycle-badge"

import {
  PIB_PIVOT_ASSET_COLUMNS,
  pivotAssetTotal,
  pivotInferredValue,
  pivotUnmappedCount,
  type PibPivotAssetBucketKey,
  type PibPivotRow,
} from "../_lib/pib-pivot-data"
import type { PibPivotDetailTarget } from "./pib-pivot-detail-dialog"
import { PibSummaryCalcHelp } from "./pib-summary-calc-help"

/**
 * Individual-portfolio view of the PIB report: one client, so instead of the pivot grid it shows how
 * the total is built (assigned + inferred), where it sits (allocation) and the holdings behind every
 * bucket. The corporate view keeps the pivot sheet.
 *
 * Bucket colours are the validated categorical palette in fixed bucket order (a bucket keeps its colour
 * whatever else is on screen); "Others" is neutral. Amounts and shares are always printed next to the
 * colour, so identity never rests on colour alone.
 */
const PALETTE_CSS = `
.pib-viz {
  --pv-moneyMarket: #2a78d6; --pv-equities: #eb6834; --pv-fixedIncome: #1baf7a; --pv-derivatives: #eda100;
  --pv-funds: #e87ba4; --pv-structuredProducts: #008300; --pv-realEstate: #4a3aa7; --pv-cryptoTokens: #e34948;
  --pv-others: #8a8985;
}
.dark .pib-viz {
  --pv-moneyMarket: #3987e5; --pv-equities: #d95926; --pv-fixedIncome: #199e70; --pv-derivatives: #c98500;
  --pv-funds: #d55181; --pv-structuredProducts: #008300; --pv-realEstate: #9085e9; --pv-cryptoTokens: #e66767;
  --pv-others: #a3a29b;
}
`

function n(value: number | null | undefined): number {
  return value == null || !Number.isFinite(value) ? 0 : value
}

function money(value: number | null | undefined): string {
  return formatAccounting(value, EM_DASH)
}

function percent(value: number): string {
  return `${value.toFixed(1)}%`
}

type BucketSummary = {
  key: PibPivotAssetBucketKey
  label: string
  code: string
  amount: number
  inferredValue: number
  inferredCount: number
  /** Per bank, only banks that hold something in this bucket. */
  byBank: { bank: string; customerId: number; amount: number }[]
}

type BankSummary = { bank: string; total: number; loanLiability: number }

function summarise(rows: PibPivotRow[]) {
  const buckets: BucketSummary[] = PIB_PIVOT_ASSET_COLUMNS.map((col) => {
    const key = col.key as PibPivotAssetBucketKey
    const byBank: BucketSummary["byBank"] = []
    let amount = 0
    let inferredValue = 0
    let inferredCount = 0
    for (const row of rows) {
      const value = n(row[key] as number | null)
      amount += value
      inferredValue += pivotInferredValue(row, key)
      inferredCount += pivotUnmappedCount(row, key)
      if (value !== 0) {
        byBank.push({ bank: row.bank, customerId: row.customerId ?? 0, amount: value })
      }
    }
    return { key, label: col.shortLabel, code: col.code, amount, inferredValue, inferredCount, byBank }
  })

  const banks: BankSummary[] = rows
    .map((row) => ({ bank: row.bank, total: pivotAssetTotal(row), loanLiability: n(row.loanLiability) }))
    .sort((a, b) => b.total - a.total)

  const total = buckets.reduce((sum, b) => sum + b.amount, 0)
  const clientName = rows.map((r) => r.client.trim()).find(Boolean) ?? ""
  const customerId = rows.map((r) => r.customerId ?? 0).find((id) => id > 0) ?? 0

  return { buckets, banks, total, clientName, customerId }
}

function bucketColor(key: PibPivotAssetBucketKey): string {
  return `var(--pv-${key})`
}

function Swatch({ bucket, className }: { bucket: PibPivotAssetBucketKey; className?: string }) {
  return (
    <span
      aria-hidden
      className={cn("inline-block size-2.5 shrink-0 rounded-[3px]", className)}
      style={{ background: bucketColor(bucket) }}
    />
  )
}

function EquationTerm({
  label,
  value,
  tone,
  hint,
}: {
  label: string
  value: string
  tone: "total" | "assigned" | "inferred" | "loan"
  hint: string
}) {
  return (
    <div className="min-w-[7.5rem]" title={hint}>
      <p
        className={cn(
          "flex items-center gap-1.5 font-medium text-[11px] uppercase tracking-wider",
          tone === "inferred" ? "text-amber-700 dark:text-amber-400" : "text-muted-foreground"
        )}
      >
        {tone === "inferred" ? <span className="inline-block size-1.5 rounded-full bg-amber-500" aria-hidden /> : null}
        {label}
      </p>
      <p
        className={cn(
          "mt-1 font-semibold tabular-nums tracking-tight",
          tone === "total" ? "text-2xl text-emerald-700 dark:text-emerald-400" : "text-lg text-foreground",
          tone === "loan" && "text-red-600 dark:text-red-400"
        )}
      >
        {value}
      </p>
    </div>
  )
}

function Operator({ children }: { children: React.ReactNode }) {
  return (
    <span aria-hidden className="self-end pb-0.5 font-light text-2xl text-muted-foreground/60 leading-none">
      {children}
    </span>
  )
}

export function PibIndividualOverview({
  rows,
  currency,
  totalAssets,
  assigned,
  inferred,
  potential = 0,
  loanLiability,
  aumMode,
  periodLabel,
  onOpenDetail,
}: {
  rows: PibPivotRow[]
  currency: string
  totalAssets: number
  assigned: number
  inferred: number
  /** Structured Products Potential calc — shown, not in PIB totals. */
  potential?: number
  loanLiability: number
  /** gross: total = assets only; net: total = assets less Loan / Overdraft. */
  aumMode: "gross" | "net"
  periodLabel: string
  /** Omitted when the role lacks the "PIB Pivot Detail API" grant — buckets then do not drill. */
  onOpenDetail?: (target: PibPivotDetailTarget) => void
}) {
  const summary = React.useMemo(() => summarise(rows), [rows])
  const [hovered, setHovered] = React.useState<PibPivotAssetBucketKey | null>(null)

  const present = summary.buckets.filter((b) => b.amount !== 0)
  const positiveTotal = present.reduce((sum, b) => sum + Math.max(b.amount, 0), 0)
  const hasNegative = present.some((b) => b.amount < 0)

  const openBucket = (bucket: BucketSummary, bank: string, amount: number) => {
    if (!onOpenDetail || summary.customerId <= 0 || bank.trim() === "") return
    onOpenDetail({
      bucket: bucket.key,
      bucketLabel: bucket.label,
      customerId: summary.customerId,
      bank,
      client: summary.clientName,
      cellValue: amount,
    })
  }

  return (
    <div className="pib-viz flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto pr-1 pb-2">
      <style>{PALETTE_CSS}</style>

      {/* How the total is built */}
      <section className="rounded-xl border border-border/80 bg-card p-4 shadow-sm sm:p-5" aria-label="Total assets advised">
        <div className="flex flex-wrap items-start justify-between gap-3">
          <div className="min-w-0">
            <p className="inline-flex items-center gap-1.5 font-semibold text-[11px] text-emerald-700 uppercase tracking-wider dark:text-emerald-400">
              B410_7001T — Total assets advised
              <PibSummaryCalcHelp
                currency={currency}
                totalAssets={totalAssets}
                assigned={assigned}
                inferred={inferred}
                potential={potential}
                loanLiability={loanLiability}
                aumMode={aumMode}
              />
            </p>
            <h2 className="mt-1 truncate font-semibold text-lg tracking-tight">
              {summary.clientName || "Your portfolio"}
            </h2>
            <p className="text-muted-foreground text-xs">
              {periodLabel} · {currency}
              {summary.banks.length > 0
                ? ` · ${summary.banks.length} bank${summary.banks.length === 1 ? "" : "s"}`
                : ""}
            </p>
          </div>
        </div>

        <div className="mt-4 flex flex-wrap items-end gap-x-5 gap-y-3 sm:gap-x-7">
          <EquationTerm
            label="Assigned"
            value={money(assigned)}
            tone="assigned"
            hint="Holdings whose PIB class is assigned on the holding or the ISIN master"
          />
          <Operator>+</Operator>
          <EquationTerm
            label="Inferred"
            value={money(inferred)}
            tone="inferred"
            hint="Holdings bucketed from asset-class rules because no PIB class is assigned"
          />
          {aumMode === "net" ? (
            <>
              <Operator>+</Operator>
              <EquationTerm
                label="Loan / Overdraft"
                value={money(loanLiability)}
                tone="loan"
                hint="Negative cash and leverage, deducted because AUM is set to Net"
              />
            </>
          ) : null}
          <Operator>=</Operator>
          <EquationTerm
            label={aumMode === "net" ? "Net assets advised" : "Total assets advised"}
            value={`${currency} ${money(totalAssets)}`}
            tone="total"
            hint={
              aumMode === "net"
                ? "Assets less Loan / Overdraft — the Overall Summary total in Net AUM mode"
                : "Sum of every bucket below, Loan / Overdraft excluded — the Overall Summary total in Gross AUM mode"
            }
          />
        </div>

        <div className="mt-4 flex flex-wrap items-center gap-x-5 gap-y-2 border-t pt-3 text-xs text-muted-foreground">
          {potential !== 0 ? (
            <span
              className="inline-flex items-center gap-1.5"
              title="Structured Products Potential · shown, not in PIB totals"
            >
              <ReportLifecycleBadge kind="potential" className="pointer-events-none" />
              <span className="font-medium tabular-nums text-amber-900 dark:text-amber-200">
                {money(potential)}
              </span>
            </span>
          ) : null}
          <span className="inline-flex items-center gap-1.5">
            <span>
              Loan / Overdraft
              <span className="ml-1 opacity-70">
                {aumMode === "net" ? "(in net total)" : "(outside total)"}
              </span>
            </span>
            <span
              className={cn(
                "font-medium tabular-nums",
                loanLiability < 0 ? "text-red-600 dark:text-red-400" : "text-foreground"
              )}
            >
              {money(loanLiability)}
            </span>
          </span>
        </div>
      </section>

      {/* Where it sits */}
      <section className="rounded-xl border border-border/80 bg-card p-4 shadow-sm sm:p-5" aria-label="Allocation">
        <h3 className="font-semibold text-sm">Allocation by PIB bucket</h3>
        <div
          className="mt-3 flex h-3.5 w-full gap-0.5 overflow-hidden"
          role="img"
          aria-label={present
            .filter((b) => b.amount > 0)
            .map((b) => `${b.label} ${percent((b.amount / positiveTotal) * 100)}`)
            .join(", ")}
        >
          {present
            .filter((b) => b.amount > 0)
            .map((b, index, all) => (
              <button
                type="button"
                key={b.key}
                title={`${b.label}: ${money(b.amount)} (${percent((b.amount / positiveTotal) * 100)})`}
                onMouseEnter={() => setHovered(b.key)}
                onMouseLeave={() => setHovered(null)}
                onFocus={() => setHovered(b.key)}
                onBlur={() => setHovered(null)}
                className={cn(
                  "h-full min-w-[3px] transition-opacity focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-ring",
                  index === all.length - 1 && "rounded-r-[4px]",
                  hovered !== null && hovered !== b.key && "opacity-40"
                )}
                style={{ width: `${(b.amount / positiveTotal) * 100}%`, background: bucketColor(b.key) }}
              />
            ))}
        </div>
        <ul className="mt-3 flex flex-wrap gap-x-4 gap-y-1.5 text-xs">
          {present.map((b) => (
            <li
              key={b.key}
              onMouseEnter={() => setHovered(b.key)}
              onMouseLeave={() => setHovered(null)}
              className={cn(
                "flex items-center gap-1.5 transition-opacity",
                hovered !== null && hovered !== b.key && "opacity-50"
              )}
            >
              <Swatch bucket={b.key} />
              <span className="text-muted-foreground">{b.label}</span>
              <span className="font-medium tabular-nums text-foreground">
                {summary.total !== 0 ? percent((b.amount / summary.total) * 100) : EM_DASH}
              </span>
            </li>
          ))}
        </ul>
        {hasNegative ? (
          <p className="mt-2 text-[11px] text-muted-foreground">
            Buckets with a negative value are listed but not drawn in the bar.
          </p>
        ) : null}
      </section>

      {/* The numbers and holdings behind each bucket */}
      <section aria-label="Buckets">
        <h3 className="mb-2 font-semibold text-sm">What is in each bucket</h3>
        <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
          {present.map((bucket) => {
            const share = summary.total !== 0 ? (bucket.amount / summary.total) * 100 : 0
            const canDrill = summary.customerId > 0
            const single = bucket.byBank.length === 1 ? bucket.byBank[0] : null
            return (
              <article
                key={bucket.key}
                onMouseEnter={() => setHovered(bucket.key)}
                onMouseLeave={() => setHovered(null)}
                className={cn(
                  "flex flex-col gap-3 rounded-xl border border-border/80 bg-card p-4 shadow-sm transition-opacity",
                  hovered !== null && hovered !== bucket.key && "opacity-60"
                )}
              >
                <header className="flex items-start justify-between gap-2">
                  <div className="min-w-0">
                    <p className="flex items-center gap-2 font-medium text-sm">
                      <Swatch bucket={bucket.key} />
                      <span className="truncate">{bucket.label}</span>
                    </p>
                    <p className="mt-0.5 font-mono text-[10px] text-muted-foreground">{bucket.code}</p>
                  </div>
                  <span className="shrink-0 font-medium text-muted-foreground text-xs tabular-nums">
                    {percent(share)}
                  </span>
                </header>

                <p
                  className={cn(
                    "font-semibold text-xl tabular-nums tracking-tight",
                    bucket.amount < 0 ? "text-red-600 dark:text-red-400" : "text-foreground"
                  )}
                >
                  {money(bucket.amount)}
                </p>

                <div className="h-1.5 w-full rounded-full bg-muted" aria-hidden>
                  <div
                    className="h-full rounded-full"
                    style={{
                      width: `${Math.min(Math.max(share, 0), 100)}%`,
                      background: bucketColor(bucket.key),
                    }}
                  />
                </div>

                {bucket.inferredValue > 0 ? (
                  <p
                    className="flex items-center gap-1.5 rounded-md bg-amber-50 px-2 py-1 text-[11px] text-amber-800 dark:bg-amber-950/40 dark:text-amber-300"
                    title="No PIB class assigned — bucketed from asset-class rules"
                  >
                    <span className="inline-block size-1.5 shrink-0 rounded-full bg-amber-500" aria-hidden />
                    Inferred {money(bucket.inferredValue)}
                    {bucket.inferredCount > 0
                      ? ` · ${bucket.inferredCount} holding${bucket.inferredCount === 1 ? "" : "s"}`
                      : ""}
                  </p>
                ) : null}

                {canDrill && single ? (
                  <button
                    type="button"
                    onClick={() => openBucket(bucket, single.bank, single.amount)}
                    className="mt-auto inline-flex items-center gap-1 self-start font-medium text-primary text-xs hover:underline"
                  >
                    View holdings
                    <ArrowRight className="size-3.5" />
                  </button>
                ) : canDrill && bucket.byBank.length > 1 ? (
                  <ul className="mt-auto divide-y rounded-lg border text-xs">
                    {bucket.byBank.map((entry) => (
                      <li key={entry.bank}>
                        <button
                          type="button"
                          onClick={() => openBucket(bucket, entry.bank, entry.amount)}
                          className="flex w-full items-center justify-between gap-2 px-2.5 py-1.5 text-left hover:bg-muted/60"
                          title={`View ${bucket.label} holdings at ${entry.bank}`}
                        >
                          <span className="truncate text-muted-foreground">{entry.bank}</span>
                          <span
                            className={cn(
                              "shrink-0 font-medium tabular-nums",
                              entry.amount < 0 ? "text-red-600 dark:text-red-400" : "text-foreground"
                            )}
                          >
                            {money(entry.amount)}
                          </span>
                        </button>
                      </li>
                    ))}
                  </ul>
                ) : null}
              </article>
            )
          })}
        </div>
      </section>

      {/* Per bank */}
      {summary.banks.length > 1 ? (
        <section className="rounded-xl border border-border/80 bg-card p-4 shadow-sm sm:p-5" aria-label="By bank">
          <h3 className="mb-2 font-semibold text-sm">By bank</h3>
          <ul className="divide-y text-sm">
            {summary.banks.map((bank) => (
              <li key={bank.bank} className="flex flex-wrap items-center justify-between gap-2 py-2">
                <span className="flex items-center gap-2">
                  <Landmark className="size-4 text-muted-foreground" aria-hidden />
                  {bank.bank || EM_DASH}
                </span>
                <span className="flex items-center gap-4 tabular-nums">
                  <span className="text-muted-foreground text-xs">
                    {summary.total !== 0 ? percent((bank.total / summary.total) * 100) : EM_DASH}
                  </span>
                  <span className="font-medium">{money(bank.total)}</span>
                  {bank.loanLiability !== 0 ? (
                    <span className="text-red-600 text-xs dark:text-red-400" title="Loan / Overdraft">
                      {money(bank.loanLiability)}
                    </span>
                  ) : null}
                </span>
              </li>
            ))}
          </ul>
        </section>
      ) : null}
    </div>
  )
}
