"use client"

import { Plus } from "lucide-react"
import { useRouter } from "next/navigation"
import { useMemo, useState } from "react"

import { useChanged } from "@/hooks/use-changed"
import { dashboardCsrfHeader } from "@/lib/csrf.client"
import { cn } from "@/lib/utils"

import { LIST_HREF } from "./schema"

export type AcModuleOption = { code: string; label: string }

export type ATypeOptions = {
  byAc: Record<string, string[]>
  all: string[]
}

type Props = {
  id: string
  aClass: string
  aType: string
  aClassLabel: string
  moduleOptions: AcModuleOption[]
  aTypeOptions: ATypeOptions
  acAtEditAllowed: boolean
  acAtEditExcludedCodes: string[]
  className?: string
}

export function IsinAssetMasterAcAtEditors({
  id,
  aClass,
  aType,
  aClassLabel,
  moduleOptions,
  aTypeOptions,
  acAtEditAllowed,
  acAtEditExcludedCodes,
  className,
}: Props) {
  const router = useRouter()
  const [ac, setAc] = useState(aClass)
  const [at, setAt] = useState(aType)
  const [busy, setBusy] = useState(false)
  const [error, setError] = useState<string | null>(null)
  const [message, setMessage] = useState<string | null>(null)
  const [extraTypes, setExtraTypes] = useState<string[]>([])
  const [isAddOpen, setIsAddOpen] = useState(false)
  const [newAssetType, setNewAssetType] = useState("")
  const [isCreating, setIsCreating] = useState(false)

  const excluded = useMemo(
    () => new Set(acAtEditExcludedCodes),
    [acAtEditExcludedCodes]
  )

  if (useChanged(aClass)) {
    setAc(aClass)
  }
  if (useChanged(aType)) {
    setAt(aType)
  }

  const optionByCode = new Map(moduleOptions.map((opt) => [opt.code, opt]))
  if (ac && !optionByCode.has(ac)) {
    optionByCode.set(ac, { code: ac, label: aClassLabel || ac })
  }
  const allOptions = Array.from(optionByCode.values())
    .filter((opt) => !excluded.has(opt.code))
    .sort((a, b) => a.code.localeCompare(b.code))

  const atSelectOptions = useMemo(() => {
    const scoped = ac && aTypeOptions.byAc[ac]?.length
      ? aTypeOptions.byAc[ac]
      : aTypeOptions.all
    const set = new Set([...scoped, ...extraTypes])
    if (at && !set.has(at)) {
      set.add(at)
    }
    return Array.from(set).sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }))
  }, [ac, at, aTypeOptions, extraTypes])

  const dirty = ac !== aClass || at !== aType

  async function onSave() {
    if (!acAtEditAllowed || !dirty || busy || ac.trim() === "") return
    setBusy(true)
    setError(null)
    setMessage(null)
    try {
      const res = await fetch(`${LIST_HREF}/${id}/update-ac-at`, {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
          ...dashboardCsrfHeader(),
        },
        body: JSON.stringify({ id, a_class: ac.trim(), a_type: at.trim() }),
      })
      const json = await res.json().catch(() => ({}))
      if (!res.ok || json?.status === "error") {
        throw new Error(json?.message || "Could not update asset class / type.")
      }
      setMessage("Saved (locked). PIB refreshed from map.")
      router.refresh()
    } catch (e) {
      setError(e instanceof Error ? e.message : "Could not update asset class / type.")
    } finally {
      setBusy(false)
    }
  }

  async function onCreateAssetType() {
    const title = newAssetType.trim()
    if (!title) {
      setError("Enter an asset type name.")
      return
    }

    setIsCreating(true)
    setError(null)
    setMessage(null)
    try {
      const res = await fetch(
        "/dashboard/master-table/normalize-asset-types/insert-definition",
        {
        method: "POST",
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
          ...dashboardCsrfHeader(),
        },
        body: JSON.stringify({ name: title, a_class: ac.trim() }),
      })
      const json = await res.json().catch(() => ({}))
      if (!res.ok || json?.status === "error") {
        throw new Error(json?.message || "Could not add asset type.")
      }

      const label =
        typeof json?.data?.label === "string" && json.data.label.trim() !== ""
          ? json.data.label.trim()
          : title

      setExtraTypes((prev) => (prev.includes(label) ? prev : [...prev, label]))
      setAt(label)
      setNewAssetType("")
      setIsAddOpen(false)
      setMessage(`Added "${label}" to catalog — save AC / AT to apply.`)
      router.refresh()
    } catch (e) {
      setError(e instanceof Error ? e.message : "Could not add asset type.")
    } finally {
      setIsCreating(false)
    }
  }

  function onReset() {
    setAc(aClass)
    setAt(aType)
    setError(null)
    setMessage(null)
    setIsAddOpen(false)
    setNewAssetType("")
  }

  function onAcChange(next: string) {
    setAc(next)
    setMessage(null)
    const scoped = next && aTypeOptions.byAc[next]?.length
      ? aTypeOptions.byAc[next]
      : aTypeOptions.all
    if (at && scoped.length > 0 && !scoped.includes(at) && !extraTypes.includes(at)) {
      setAt("")
    }
  }

  if (!acAtEditAllowed) {
    return (
      <div className={cn("flex flex-col gap-2", className)}>
        <div className="grid gap-3 sm:grid-cols-2">
          <div>
            <dt className="text-xs text-muted-foreground">Asset Class</dt>
            <dd className="text-sm font-medium">
              {aClassLabel || aClass} ({aClass || "—"})
            </dd>
          </div>
          <div>
            <dt className="text-xs text-muted-foreground">Asset Type</dt>
            <dd className="text-sm font-medium">{aType || "—"}</dd>
          </div>
        </div>
        <p className="text-[10px] text-muted-foreground">
          AC / AT editing is disabled for structure, accumulator, decumulator, stock option,
          and FX / cash deposit classes.
        </p>
      </div>
    )
  }

  return (
    <div className={cn("flex flex-col gap-3", className)}>
      <div className="grid gap-3 sm:grid-cols-2">
        <div>
          <label className="mb-1 block text-xs text-muted-foreground" htmlFor={`ac-${id}`}>
            Asset Class
          </label>
          <select
            id={`ac-${id}`}
            className={cn(
              "h-8 w-full max-w-[18rem] rounded border border-input bg-background px-2 text-xs",
              "disabled:cursor-not-allowed disabled:opacity-50"
            )}
            value={ac}
            disabled={busy || isCreating}
            onChange={(e) => onAcChange(e.target.value)}
          >
            {ac === "" ? <option value="">—</option> : null}
            {ac && excluded.has(ac) && !allOptions.some((opt) => opt.code === ac) ? (
              <option value={ac}>
                {aClassLabel || ac} ({ac})
              </option>
            ) : null}
            {allOptions.map((opt) => (
              <option key={opt.code} value={opt.code}>
                {opt.label} ({opt.code})
              </option>
            ))}
          </select>
        </div>
        <div>
          <label className="mb-1 block text-xs text-muted-foreground" htmlFor={`at-${id}`}>
            Asset Type
          </label>
          <div className="flex max-w-[18rem] items-center gap-1.5">
            <select
              id={`at-${id}`}
              className={cn(
                "h-8 min-w-0 flex-1 rounded border border-input bg-background px-2 text-xs",
                "disabled:cursor-not-allowed disabled:opacity-50"
              )}
              value={at}
              disabled={busy || isCreating}
              onChange={(e) => {
                setAt(e.target.value)
                setMessage(null)
              }}
            >
              <option value="">—</option>
              {atSelectOptions.map((type) => (
                <option key={type} value={type}>
                  {type}
                </option>
              ))}
            </select>
            <button
              type="button"
              title="Create asset type"
              aria-label="Create asset type"
              className={cn(
                "inline-flex size-8 shrink-0 items-center justify-center rounded border border-border",
                "bg-background text-foreground hover:bg-muted",
                "disabled:cursor-not-allowed disabled:opacity-50"
              )}
              disabled={busy || isCreating || ac.trim() === ""}
              onClick={() => setIsAddOpen((prev) => !prev)}
            >
              <Plus className="size-3.5" />
            </button>
          </div>
          {isAddOpen ? (
            <div className="mt-2 flex max-w-[18rem] items-center gap-1.5">
              <input
                type="text"
                value={newAssetType}
                placeholder="Enter new asset type"
                disabled={busy || isCreating}
                className={cn(
                  "h-8 min-w-0 flex-1 rounded border border-input bg-background px-2 text-xs",
                  "disabled:cursor-not-allowed disabled:opacity-50"
                )}
                onChange={(e) => setNewAssetType(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === "Enter") {
                    e.preventDefault()
                    void onCreateAssetType()
                  }
                }}
              />
              <button
                type="button"
                className={cn(
                  "rounded border px-2 py-1 text-xs font-medium",
                  "border-sky-700/40 bg-sky-50 text-sky-950 hover:bg-sky-100",
                  "disabled:cursor-not-allowed disabled:opacity-50"
                )}
                disabled={busy || isCreating || newAssetType.trim() === ""}
                onClick={() => void onCreateAssetType()}
              >
                {isCreating ? "Adding…" : "Create"}
              </button>
            </div>
          ) : null}
          <p className="mt-1 text-[10px] text-muted-foreground">
            Options from bank XML votes{ac ? ` for ${ac}` : ""} (+ master catalog).
          </p>
        </div>
      </div>
      <div className="flex flex-wrap items-center gap-2">
        <button
          type="button"
          className={cn(
            "rounded border px-2.5 py-1 text-xs font-medium",
            "border-sky-700/40 bg-sky-50 text-sky-950 hover:bg-sky-100",
            "disabled:cursor-not-allowed disabled:opacity-50"
          )}
          disabled={!dirty || busy || isCreating || ac.trim() === ""}
          onClick={() => void onSave()}
        >
          {busy ? "Saving…" : "Save AC / AT"}
        </button>
        <button
          type="button"
          className={cn(
            "rounded border border-border bg-background px-2.5 py-1 text-xs font-medium hover:bg-muted",
            "disabled:cursor-not-allowed disabled:opacity-50"
          )}
          disabled={!dirty || busy || isCreating}
          onClick={onReset}
        >
          Reset
        </button>
        <span className="text-[10px] text-muted-foreground">
          Saving locks the row. PIB is edited separately and is not changed here.
        </span>
      </div>
      {error ? <p className="text-xs text-destructive">{error}</p> : null}
      {message ? <p className="text-xs text-muted-foreground">{message}</p> : null}
    </div>
  )
}
