"use client"

import Link from "next/link"
import { useMemo, useState } from "react"
import { ChevronDown, GitCompareArrows, X } from "lucide-react"

import { ListPageCard } from "@/app/dashboard/_components"
import { Badge } from "@/components/ui/badge"
import { Input } from "@/components/ui/input"
import { XmlApiErrorBanner } from "@/components/xml-apis/shared/xml-api-error-banner"
import type {
  IdLabelMap,
  PosReconV2AcCount,
  PosReconV2CustomerGroup,
  PosReconV2Line,
  PosReconV2Run,
} from "@/components/xml-apis/pos-recon-v2/types"
import { PosReconV2StatCards } from "@/components/xml-apis/pos-recon-v2/components/pos-recon-v2-stat-cards"

type Props = {
  runId: number
  initialRun: PosReconV2Run | null
  initialGroups: PosReconV2CustomerGroup[]
  initialCounts: Record<string, number>
  statusLabels: IdLabelMap
  initialStatus: string
  initialAc?: string
  initialQuery?: string
  corporateId: number
  initialErrorMessage?: string | null
}

const STATUS_COLORS: Record<string, string> = {
  matched: "#1e7e34",
  mismatch: "#c47b00",
  missing_in_xml: "#0d6efd",
  missing_in_oxy: "#6f42c1",
  class_mismatch: "#a15c07",
  unmapped_customer: "#b02a37",
}

const OPTION_SIDE_TAG: Record<string, string> = {
  CALL_BUY: "border-emerald-200 bg-emerald-50 text-emerald-800",
  CALL_SELL: "border-amber-200 bg-amber-50 text-amber-900",
  PUT_BUY: "border-sky-200 bg-sky-50 text-sky-900",
  PUT_SELL: "border-violet-200 bg-violet-50 text-violet-900",
}

function acSlug(title: string): string {
  const slug = title
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-+|-+$/g, "")
  return slug || "unknown"
}

function formatQty(value: number | string | null | undefined): string {
  if (value == null || value === "") return ""
  const num = Number(value)
  if (!Number.isFinite(num)) return String(value)
  return Number.isInteger(num) ? String(num) : num.toLocaleString("en-US", { maximumFractionDigits: 6 })
}

function rowHaystack(row: PosReconV2Line): string {
  return [
    row.account_number,
    row.xml_isin,
    row.oxy_isin,
    row.isin_match,
    row.asset_class,
    row.leftover_reason_label,
    row.qty_tally ? "qty tally" : "",
    row.tag_error,
  ]
    .map((v) => String(v ?? "").toLowerCase())
    .join(" ")
}

function lineMatchesFilters(
  row: PosReconV2Line,
  statusFilter: string,
  acFilter: string,
  query: string,
  customerLabel: string
): boolean {
  if (statusFilter && row.match_status !== statusFilter) return false
  if (acFilter && acSlug(row.asset_class || "") !== acFilter) return false
  if (!query) return true
  if (customerLabel.toLowerCase().includes(query)) return true
  return rowHaystack(row).includes(query)
}

function groupSummary(group: PosReconV2CustomerGroup): string {
  const parts: string[] = []
  if (group.matched_count) parts.push(`${group.matched_count} matched`)
  if (group.mismatch_count) parts.push(`${group.mismatch_count} mismatch`)
  if (group.missing_oxy_count) parts.push(`${group.missing_oxy_count} miss Oxy`)
  if (group.missing_xml_count) parts.push(`${group.missing_xml_count} miss XML`)
  if (group.class_mismatch_count) parts.push(`${group.class_mismatch_count} class mismatch`)
  if (group.unmapped_count) parts.push(`${group.unmapped_count} unmapped`)
  parts.push(`${group.row_count} total`)
  return parts.join(" · ")
}

function LineTable({
  rows,
  statusLabels,
}: {
  rows: PosReconV2Line[]
  statusLabels: IdLabelMap
}) {
  if (rows.length === 0) {
    return (
      <div className="px-4 py-6 text-center text-sm text-muted-foreground">
        No lines for this filter.
      </div>
    )
  }

  return (
    <div className="overflow-x-auto">
      <table className="min-w-full text-sm">
        <thead className="bg-muted/40 text-left">
          <tr>
            <th className="px-3 py-2 font-medium">Status</th>
            <th className="px-3 py-2 font-medium">Account</th>
            <th className="px-3 py-2 font-medium">XML ISIN</th>
            <th className="px-3 py-2 font-medium">Oxy ISIN</th>
            <th className="px-3 py-2 font-medium">AC</th>
            <th className="px-3 py-2 text-right font-medium">XML qty</th>
            <th className="px-3 py-2 text-right font-medium">OS qty</th>
            <th className="px-3 py-2 text-right font-medium">Delta</th>
            <th className="px-3 py-2 font-medium">Reason</th>
          </tr>
        </thead>
        <tbody>
          {rows.map((line, index) => {
            const color = STATUS_COLORS[line.match_status] || "#555"
            const label = statusLabels[line.match_status] || line.match_status
            return (
              <tr key={line.row_key || `${line.identity_key}-${index}`} className="border-t">
                <td className="px-3 py-2 whitespace-nowrap">
                  <span
                    className="inline-flex rounded-full px-2 py-0.5 text-xs font-medium"
                    style={{ color, backgroundColor: `${color}14` }}
                  >
                    {label}
                  </span>
                </td>
                <td className="px-3 py-2 whitespace-nowrap">{line.account_number ?? ""}</td>
                <td className="px-3 py-2 font-mono text-xs">{line.xml_isin}</td>
                <td className="px-3 py-2 font-mono text-xs">{line.oxy_isin}</td>
                <td className="px-3 py-2">
                  <div className="flex flex-wrap items-center gap-1.5">
                    <span>{line.asset_class}</span>
                    {line.option_side_label ? (
                      <Badge
                        variant="outline"
                        className={
                          OPTION_SIDE_TAG[String(line.option_side || "").toUpperCase()] ||
                          "border-border bg-muted/50 text-foreground"
                        }
                      >
                        {line.option_side_label}
                      </Badge>
                    ) : null}
                  </div>
                </td>
                <td className="px-3 py-2 text-right tabular-nums">{formatQty(line.xml_qty)}</td>
                <td className="px-3 py-2 text-right tabular-nums">{formatQty(line.os_qty)}</td>
                <td className="px-3 py-2 text-right tabular-nums">{formatQty(line.delta)}</td>
                <td className="px-3 py-2 text-muted-foreground">
                  <div className="flex flex-wrap items-center gap-1.5">
                    {line.leftover_reason_label || line.tag_error ? (
                      <span>{line.leftover_reason_label || line.tag_error}</span>
                    ) : null}
                    {line.qty_tally ? (
                      <Badge
                        variant="outline"
                        className="border-emerald-200 bg-emerald-50 text-emerald-800"
                      >
                        Qty Tally
                      </Badge>
                    ) : null}
                  </div>
                </td>
              </tr>
            )
          })}
        </tbody>
      </table>
    </div>
  )
}

function CustomerGroupPanel({
  group,
  rows,
  statusLabels,
  defaultOpen,
}: {
  group: PosReconV2CustomerGroup
  rows: PosReconV2Line[]
  statusLabels: IdLabelMap
  defaultOpen: boolean
}) {
  const [open, setOpen] = useState(defaultOpen)

  return (
    <div className="overflow-hidden rounded-md border">
      <button
        type="button"
        onClick={() => setOpen((value) => !value)}
        className="flex w-full items-center justify-between gap-3 bg-muted/30 px-4 py-3 text-left hover:bg-muted/50"
      >
        <div className="flex min-w-0 items-center gap-2">
          <ChevronDown
            className={`h-4 w-4 shrink-0 text-muted-foreground transition-transform ${open ? "" : "-rotate-90"}`}
          />
          <div className="min-w-0">
            <div className="truncate font-medium">{group.label}</div>
            <div className="mt-0.5 truncate text-xs text-muted-foreground">
              {groupSummary(group)}
            </div>
          </div>
        </div>
        <span className="shrink-0 text-xs tabular-nums text-muted-foreground">
          {rows.length}
          {rows.length !== group.row_count ? ` / ${group.row_count}` : ""}
        </span>
      </button>
      {open ? (
        <div className="border-t">
          <LineTable rows={rows} statusLabels={statusLabels} />
        </div>
      ) : null}
    </div>
  )
}

export function PosReconV2DetailPage({
  runId,
  initialRun,
  initialGroups,
  initialCounts,
  statusLabels,
  initialStatus,
  initialAc = "",
  initialQuery = "",
  corporateId,
  initialErrorMessage = null,
}: Props) {
  const [statusFilter, setStatusFilter] = useState(initialStatus)
  const [acFilter, setAcFilter] = useState(initialAc)
  const [query, setQuery] = useState(initialQuery)

  const normalizedQuery = query.trim().toLowerCase()

  // AC chips follow the status card above (Mismatch → only mismatch ACs / counts).
  const acOptions = useMemo(() => {
    const map = new Map<string, PosReconV2AcCount>()
    for (const group of initialGroups) {
      for (const row of group.rows) {
        if (statusFilter && row.match_status !== statusFilter) continue
        if (
          normalizedQuery &&
          !group.label.toLowerCase().includes(normalizedQuery) &&
          !rowHaystack(row).includes(normalizedQuery)
        ) {
          continue
        }
        const label = (row.asset_class || "").trim() || "Unknown"
        const slug = acSlug(label)
        const existing = map.get(slug)
        if (existing) {
          existing.count += 1
        } else {
          map.set(slug, { label, slug, count: 1 })
        }
      }
    }
    return Array.from(map.values()).sort((a, b) => b.count - a.count || a.label.localeCompare(b.label))
  }, [initialGroups, statusFilter, normalizedQuery])

  const visibleGroups = useMemo(() => {
    return initialGroups
      .map((group) => ({
        group,
        rows: group.rows.filter((row) =>
          lineMatchesFilters(row, statusFilter, acFilter, normalizedQuery, group.label)
        ),
      }))
      .filter((item) => item.rows.length > 0)
  }, [initialGroups, statusFilter, acFilter, normalizedQuery])

  const visibleLineCount = useMemo(
    () => visibleGroups.reduce((sum, item) => sum + item.rows.length, 0),
    [visibleGroups]
  )

  function syncUrl(nextStatus: string, nextAc: string, nextQuery: string) {
    const params = new URLSearchParams()
    if (nextStatus) params.set("status", nextStatus)
    if (nextAc) params.set("ac", nextAc)
    if (nextQuery.trim()) params.set("q", nextQuery.trim())
    if (corporateId) params.set("corporate_id", String(corporateId))
    const qs = params.toString()
    window.history.replaceState(
      null,
      "",
      `/dashboard/xml-apis/pos-recon-v2/${runId}${qs ? `?${qs}` : ""}`
    )
  }

  function onSelectStatus(status: string) {
    setStatusFilter(status)
    // Drop AC if it has no rows under the new status (counts recompute below).
    const nextAc =
      acFilter &&
      !initialGroups.some((g) =>
        g.rows.some(
          (row) =>
            (!status || row.match_status === status) && acSlug(row.asset_class || "") === acFilter
        )
      )
        ? ""
        : acFilter
    if (nextAc !== acFilter) setAcFilter(nextAc)
    syncUrl(status, nextAc, query)
  }

  function onSelectAc(slug: string) {
    const next = acFilter === slug ? "" : slug
    setAcFilter(next)
    syncUrl(statusFilter, next, query)
  }

  function clearFilters() {
    setStatusFilter("")
    setAcFilter("")
    setQuery("")
    syncUrl("", "", "")
  }

  const hasFilters = Boolean(statusFilter || acFilter || query.trim())

  const backHref = corporateId
    ? `/dashboard/xml-apis/pos-recon-v2?corporate_id=${corporateId}`
    : "/dashboard/xml-apis/pos-recon-v2"

  return (
    <ListPageCard
      icon={GitCompareArrows}
      title={`POS Recon v2 · Run #${runId}`}
      description={
        initialRun
          ? `Upload #${initialRun.upload_id ?? "—"} · as-of ${initialRun.as_of_date ?? "—"} · ${(initialRun.mapping_mode || "bank") === "common" ? "Common Detect" : "Normal"} · ${initialRun.status ?? ""}`
          : "Run detail"
      }
      breadcrumb={[
        { label: "XML API" },
        { label: "POS Recon v2", href: backHref },
        { label: `Run #${runId}` },
      ]}
      actions={
        <Link href={backHref} className="text-sm text-muted-foreground hover:text-foreground">
          Back to runs
        </Link>
      }
    >
      <XmlApiErrorBanner message={initialErrorMessage} />
      <PosReconV2StatCards
        counts={initialCounts}
        activeStatus={statusFilter}
        onSelectStatus={onSelectStatus}
        totalXml={initialCounts.xml_rows}
        totalOs={initialCounts.os_rows}
      />

      <div className="mt-4 space-y-3 rounded-md border bg-muted/20 p-3">
        <div className="flex flex-wrap items-center gap-2">
          <Input
            value={query}
            onChange={(e) => {
              const next = e.target.value
              setQuery(next)
              syncUrl(statusFilter, acFilter, next)
            }}
            placeholder="Search customer, account, ISIN…"
            className="max-w-md bg-background"
          />
          {hasFilters ? (
            <button
              type="button"
              onClick={clearFilters}
              className="inline-flex h-8 items-center gap-1 rounded-md border bg-background px-2.5 text-xs text-muted-foreground hover:text-foreground"
            >
              <X className="h-3.5 w-3.5" />
              Clear filters
            </button>
          ) : null}
          <span className="ml-auto text-xs text-muted-foreground">
            {visibleGroups.length} customer{visibleGroups.length === 1 ? "" : "s"} ·{" "}
            {visibleLineCount} line{visibleLineCount === 1 ? "" : "s"}
          </span>
        </div>
        {acOptions.length > 0 ? (
          <div className="flex flex-wrap items-center gap-1.5">
            <span className="mr-1 text-xs font-medium text-muted-foreground">Asset class</span>
            <button
              type="button"
              onClick={() => onSelectAc("")}
              className={`rounded-md border px-2 py-1 text-xs transition-colors ${
                !acFilter
                  ? "border-foreground bg-foreground text-background"
                  : "border-border bg-background text-muted-foreground hover:text-foreground"
              }`}
            >
              All
            </button>
            {acOptions.map((ac) => {
              const active = acFilter === ac.slug
              return (
                <button
                  key={ac.slug}
                  type="button"
                  onClick={() => onSelectAc(ac.slug)}
                  className={`rounded-md border px-2 py-1 text-xs transition-colors ${
                    active
                      ? "border-foreground bg-foreground text-background"
                      : "border-border bg-background text-muted-foreground hover:text-foreground"
                  }`}
                >
                  {ac.label}{" "}
                  <span className={active ? "opacity-80" : "text-foreground/70"}>{ac.count}</span>
                </button>
              )
            })}
          </div>
        ) : null}
      </div>

      <div className="mt-3 space-y-2">
        {visibleGroups.length === 0 ? (
          <div className="rounded-md border px-4 py-8 text-center text-sm text-muted-foreground">
            No customers match these filters.
          </div>
        ) : (
          visibleGroups.map(({ group, rows }, index) => (
            <CustomerGroupPanel
              key={group.key}
              group={group}
              rows={rows}
              statusLabels={statusLabels}
              defaultOpen={index === 0}
            />
          ))
        )}
      </div>
    </ListPageCard>
  )
}
