import Link from "next/link"
import { notFound } from "next/navigation"
import { Percent } from "lucide-react"

import { ListPageCard } from "@/app/dashboard/_components"
import { ErrorBanner } from "@/components/shared/error-banner"
import { BACKEND_ENDPOINTS } from "@/config/backend-endpoints"
import { fetchAuthenticatedBackendJson } from "@/lib/backend-client"
import { isRecord, stringOrEmpty } from "@/lib/server-utils"

import {
  IsinAssetMasterAcAtEditors,
  type MacroAcOption,
} from "../_components/isin-asset-master-ac-at-editors"
import { IsinAssetMasterDetailActions } from "../_components/isin-asset-master-detail-actions"
import { IsinAssetMasterPibSelect } from "../_components/isin-asset-master-pib-select"
import { parseDetectFields } from "../_lib/detect-provenance"
import {
  normalizeATypeOptions,
  normalizeDefaultAtByAc,
  normalizeExcludedCodes,
  normalizeMacroOptions,
  normalizeModuleOptions,
} from "../_lib/isin-asset-master-options"
import { normalizePibClassList } from "../_lib/pib-class-options"
import {
  LIST_HREF,
  type DetectAcProvenance,
  type DetectAtProvenance,
} from "../_components/schema"

type PageProps = { params: Promise<{ id: string }> }

export default async function IsinAssetMasterDetailPage({ params }: PageProps) {
  const { id } = await params
  const result = await fetchDetail(id)
  if (result.notFound) notFound()

  const model = result.model
  const probabilities = result.probabilities
  const pibClassList = result.pibClassList
  const moduleOptions = result.moduleOptions
  const macroOptions = result.macroOptions
  const defaultAtByAc = result.defaultAtByAc
  const aTypeOptions = result.aTypeOptions
  const acAtEditAllowed = result.acAtEditAllowed
  const acAtEditExcludedCodes = result.acAtEditExcludedCodes
  const isinNames = Array.from(
    new Set(
      probabilities.rows
        .map((row) => row.isin_name.trim())
        .filter((name) => name !== "")
    )
  )
  if (isinNames.length === 0 && model.isinName) {
    isinNames.push(model.isinName)
  }

  return (
    <ListPageCard
      icon={Percent}
      title={
        model.isin
          ? `${model.isin}${model.isinName ? ` · ${model.isinName}` : ""} · ${probabilities.bank_count} bank${probabilities.bank_count === 1 ? "" : "s"}`
          : id
      }
      description={`${probabilities.bank_count} bank vote${probabilities.bank_count === 1 ? "" : "s"}; computed probabilities, lock / edit.`}
      breadcrumb={[
        { label: "Master Table" },
        { label: "ISIN Asset Master", href: LIST_HREF },
        { label: model.isin || id },
      ]}
      actions={
        <IsinAssetMasterDetailActions
          id={model.id}
          status={model.status}
          acAtEditAllowed={acAtEditAllowed}
          aClass={model.aClassLabel || model.aClass}
          aType={model.aType}
          pibClass={model.pibClassLabel || model.pibClass}
          isin={model.isin}
        />
      }
    >
      <ErrorBanner message={result.errorMessage} className="mb-4" />
      <div className="mb-4">
        <Link href={LIST_HREF} className="text-sm text-sky-700 hover:underline">
          Back to list
        </Link>
      </div>
      <dl className="mb-6 grid gap-3 rounded-lg border bg-card p-4 sm:grid-cols-2">
        <div>
          <dt className="text-xs text-muted-foreground">ISIN Name{isinNames.length > 1 ? "s" : ""}</dt>
          <dd className="text-sm font-medium">
            {isinNames.length === 0 ? (
              "—"
            ) : (
              <ul className="space-y-0.5">
                {isinNames.map((name) => (
                  <li key={name}>{name}</li>
                ))}
              </ul>
            )}
          </dd>
        </div>
        <div>
          <dt className="mb-1 text-xs text-muted-foreground">PIB</dt>
          <dd>
            <IsinAssetMasterPibSelect
              id={model.id}
              value={model.pibClass}
              options={pibClassList}
            />
          </dd>
        </div>
        <div>
          <dt className="text-xs text-muted-foreground">Status</dt>
          <dd className="text-sm font-medium">
            {model.statusLabel}
            {!acAtEditAllowed ? (
              <span
                className="ml-2 inline-flex rounded-md bg-slate-100 px-1.5 py-0.5 text-[10px] font-medium text-slate-700 ring-1 ring-slate-400/30"
                title="Structure & others — Skipped (assign PIB only; no Update transactions)"
              >
                Skipped
              </span>
            ) : null}
            {model.detectFlagged ? (
              <span
                className="ml-2 inline-flex rounded-md bg-rose-100 px-1.5 py-0.5 text-[10px] font-medium text-rose-900 ring-1 ring-rose-600/25"
                title="AT Detect Flag IAM rule matched on common_auto"
              >
                Flagged
              </span>
            ) : null}
          </dd>
        </div>
        <div>
          <dt className="text-xs text-muted-foreground">AC Confidence %</dt>
          <dd className="text-sm font-medium">
            {model.confidenceAc == null ? "—" : model.confidenceAc}
          </dd>
        </div>
        <div>
          <dt className="text-xs text-muted-foreground">AT Confidence %</dt>
          <dd className="text-sm font-medium">
            {model.confidenceAt == null ? "—" : model.confidenceAt}
          </dd>
        </div>
        <div>
          <dt className="text-xs text-muted-foreground">Updated</dt>
          <dd className="text-sm font-medium">{model.updatedAt || "—"}</dd>
        </div>
      </dl>

      <div className="mb-6 rounded-lg border bg-card p-4">
        <IsinAssetMasterAcAtEditors
          id={model.id}
          aClass={model.aClass}
          aType={model.aType}
          aClassLabel={model.aClassLabel}
          macroAssetClass={model.macroAssetClass}
          macroOptions={macroOptions}
          defaultAtByAc={defaultAtByAc}
          moduleOptions={moduleOptions}
          aTypeOptions={aTypeOptions}
          acAtEditAllowed={acAtEditAllowed}
          acAtEditExcludedCodes={acAtEditExcludedCodes}
          detectAc={model.detectAc}
          detectAt={model.detectAt}
          detectFlagged={model.detectFlagged}
        />
      </div>

      <h3 className="mb-2 text-sm font-semibold">AC probabilities</h3>
      <ul className="mb-6 space-y-1 rounded-lg border bg-card p-4 text-sm">
        {Object.keys(probabilities.ac).length === 0 ? (
          <li className="text-muted-foreground">No bank votes yet.</li>
        ) : (
          Object.entries(probabilities.ac).map(([code, pct]) => (
            <li key={code} className="flex justify-between font-mono">
              <span>{code}</span>
              <span>{pct}%</span>
            </li>
          ))
        )}
      </ul>

      <h3 className="mb-2 text-sm font-semibold">AT probabilities (within winning AC)</h3>
      <ul className="mb-6 space-y-1 rounded-lg border bg-card p-4 text-sm">
        {Object.keys(probabilities.at ?? {}).length === 0 ? (
          <li className="text-muted-foreground">No asset-type votes for the winning AC.</li>
        ) : (
          Object.entries(probabilities.at ?? {}).map(([type, pct]) => (
            <li key={type} className="flex justify-between font-mono">
              <span>{type}</span>
              <span>{pct}%</span>
            </li>
          ))
        )}
      </ul>

      <h3 className="mb-2 text-sm font-semibold">
        Bank votes ({probabilities.bank_count})
      </h3>
      <div className="overflow-x-auto rounded-lg border bg-card">
        <table className="w-full text-left text-sm">
          <thead className="border-b bg-muted/40 text-xs text-muted-foreground">
            <tr>
              <th className="px-3 py-2">Bank</th>
              <th className="px-3 py-2">ISIN Name</th>
              <th className="px-3 py-2">Category</th>
              <th className="px-3 py-2">AC</th>
              <th className="px-3 py-2">AT</th>
              <th className="px-3 py-2">Source</th>
              <th className="px-3 py-2">Updated</th>
            </tr>
          </thead>
          <tbody>
            {probabilities.rows.length === 0 ? (
              <tr>
                <td colSpan={7} className="px-3 py-6 text-center text-muted-foreground">
                  No assignment rows.
                </td>
              </tr>
            ) : (
              probabilities.rows.map((row) => (
                <tr key={`${row.isin}-${row.bank_api_id}`} className="border-b last:border-0">
                  <td className="px-3 py-2">
                    <div className="font-medium">{row.bank_name || `Bank #${row.bank_api_id}`}</div>
                    <div className="font-mono text-xs text-muted-foreground">
                      ID {row.bank_api_id}
                    </div>
                  </td>
                  <td className="px-3 py-2">{row.isin_name || "—"}</td>
                  <td className="px-3 py-2">{row.api_category}</td>
                  <td className="px-3 py-2 font-mono">{row.a_class}</td>
                  <td className="px-3 py-2">
                    {(row.a_type_normalized && row.a_type_normalized.trim()) ||
                      row.a_type ||
                      "—"}
                    {row.a_type_normalized &&
                    row.a_type &&
                    row.a_type_normalized.trim() !== "" &&
                    row.a_type_normalized !== row.a_type ? (
                      <div className="mt-0.5 text-xs text-muted-foreground">
                        Raw: {row.a_type}
                      </div>
                    ) : null}
                  </td>
                  <td className="px-3 py-2">{row.source}</td>
                  <td className="px-3 py-2 text-xs">{row.updated_at}</td>
                </tr>
              ))
            )}
          </tbody>
        </table>
      </div>
    </ListPageCard>
  )
}

async function fetchDetail(id: string) {
  const { response, status, errorMessage } = await fetchAuthenticatedBackendJson<{
    status?: string
    message?: string
    data?: unknown
  }>({
    endpoint: BACKEND_ENDPOINTS.masterTable.isinAssetMaster.view,
    method: "POST",
    body: { id },
    invalidMessage: "Failed to load master detail.",
    unavailableMessage: "Failed to load master detail.",
    timeoutMessage: "Master detail timed out.",
    connectionMessage: "Could not connect for master detail.",
  })

  if (status === 404) {
    return { notFound: true as const }
  }

  if (!response || response.status !== "success" || !isRecord(response.data)) {
    return {
      notFound: false as const,
      errorMessage:
        errorMessage || stringOrEmpty(response?.message) || "Failed to load master detail.",
      model: emptyModel(id),
      pibClassList: [] as ReturnType<typeof normalizePibClassList>,
      moduleOptions: [] as { code: string; label: string }[],
      macroOptions: [] as MacroAcOption[],
      defaultAtByAc: {} as Record<string, string>,
      aTypeOptions: { byAc: {}, all: [] as string[] },
      acAtEditAllowed: true,
      acAtEditExcludedCodes: [] as string[],
      probabilities: { ac: {}, at: {}, bank_count: 0, a_type: null, rows: [] as VoteRow[] },
    } as const
  }

  const data = response.data
  const modelRaw = isRecord(data.model) ? data.model : {}
  const probsRaw = isRecord(data.probabilities) ? data.probabilities : {}
  const pibClassList = normalizePibClassList(data.pibClassList)
  const moduleOptions = normalizeModuleOptions(data.moduleNames)
  const macroOptions = normalizeMacroOptions(data.macroOptions)
  const defaultAtByAc = normalizeDefaultAtByAc(data.defaultAtByAc)
  const aTypeOptions = normalizeATypeOptions(data.aTypeOptions)
  const acAtEditAllowed = data.acAtEditAllowed !== false
  const acAtEditExcludedCodes = normalizeExcludedCodes(data.acAtEditExcludedCodes)
  const acRaw = isRecord(probsRaw.ac) ? probsRaw.ac : {}
  const ac: Record<string, number> = {}
  for (const [k, v] of Object.entries(acRaw)) {
    ac[k] = Number(v)
  }
  const atRaw = isRecord(probsRaw.at) ? probsRaw.at : {}
  const at: Record<string, number> = {}
  for (const [k, v] of Object.entries(atRaw)) {
    at[k] = Number(v)
  }
  const rows: VoteRow[] = Array.isArray(probsRaw.rows)
    ? probsRaw.rows.filter(isRecord).map((r) => ({
        isin: stringOrEmpty(r.isin),
        isin_name: stringOrEmpty(r.isin_name),
        bank_api_id: Number(r.bank_api_id),
        bank_name: stringOrEmpty(r.bank_name),
        api_category: stringOrEmpty(r.api_category),
        a_class: stringOrEmpty(r.a_class),
        a_type: stringOrEmpty(r.a_type),
        a_type_normalized: stringOrEmpty(r.a_type_normalized) || null,
        source: stringOrEmpty(r.source),
        updated_at: stringOrEmpty(r.updated_at),
      }))
    : []

  return {
    notFound: false as const,
    errorMessage: null as string | null,
    model: {
      id: stringOrEmpty(modelRaw.id) || id,
      isin: stringOrEmpty(modelRaw.isin),
      isinName: stringOrEmpty(modelRaw.isin_name),
      aClass: stringOrEmpty(modelRaw.a_class),
      aClassLabel: stringOrEmpty(data.a_class_label) || stringOrEmpty(modelRaw.a_class),
      macroAssetClass:
        stringOrEmpty(data.macro_asset_class) ||
        stringOrEmpty(modelRaw.macro_asset_class),
      aType: stringOrEmpty(modelRaw.a_type),
      aTypeNormalized: stringOrEmpty(modelRaw.a_type_normalized),
      pibClass: stringOrEmpty(modelRaw.pib_class),
      pibClassLabel:
        stringOrEmpty(data.pib_class_label) || stringOrEmpty(modelRaw.pib_class),
      status: stringOrEmpty(modelRaw.status),
      statusLabel:
        stringOrEmpty(
          isRecord(data.statusList) ? data.statusList[stringOrEmpty(modelRaw.status)] : ""
        ) || stringOrEmpty(modelRaw.status),
      confidenceAc:
        modelRaw.confidence_ac == null || modelRaw.confidence_ac === ""
          ? null
          : Number(modelRaw.confidence_ac),
      confidenceAt:
        modelRaw.confidence_at == null || modelRaw.confidence_at === ""
          ? null
          : Number(modelRaw.confidence_at),
      updatedAt: stringOrEmpty(modelRaw.updated_at),
      ...parseDetectFields(modelRaw),
    },
    pibClassList,
    moduleOptions,
    macroOptions,
    defaultAtByAc,
    aTypeOptions,
    acAtEditAllowed,
    acAtEditExcludedCodes,
    probabilities: {
      ac,
      at,
      bank_count: Number(probsRaw.bank_count ?? rows.length),
      a_type: probsRaw.a_type == null ? null : stringOrEmpty(probsRaw.a_type),
      rows,
    },
  }
}

type VoteRow = {
  isin: string
  isin_name: string
  bank_api_id: number
  bank_name: string
  api_category: string
  a_class: string
  a_type: string
  a_type_normalized: string | null
  source: string
  updated_at: string
}

function emptyModel(id: string) {
  return {
    id,
    isin: "",
    isinName: "",
    aClass: "",
    aClassLabel: "",
    macroAssetClass: "",
    aType: "",
    aTypeNormalized: "",
    pibClass: "",
    pibClassLabel: "",
    status: "",
    statusLabel: "",
    confidenceAc: null as number | null,
    confidenceAt: null as number | null,
    updatedAt: "",
    detectFlagged: false,
    detectAc: null as DetectAcProvenance | null,
    detectAt: null as DetectAtProvenance | null,
  }
}
