"use client"

import { errorMessageOr } from "@/lib/toast-api-error";

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
  moduleOptions: AcModuleOption[]
  aTypeOptions: ATypeOptions
  className?: string
}

export function IsinAssetMasterAcAtEditors({
  id,
  aClass,
  aType,
  moduleOptions,
  aTypeOptions,
  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)

  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: ac })
  }
  const allOptions = Array.from(optionByCode.values()).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)
    if (at && !set.has(at)) {
      set.add(at)
    }
    return Array.from(set).sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" }))
  }, [ac, at, aTypeOptions])

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

  async function onSave() {
    if (!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(errorMessageOr(e, "Could not update asset class / type."))
    } finally {
      setBusy(false)
    }
  }

  function onReset() {
    setAc(aClass)
    setAt(aType)
    setError(null)
    setMessage(null)
  }

  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)) {
      setAt("")
    }
  }

  return (
    <div className={cn("flex flex-col gap-3 sm:col-span-2", 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}
            onChange={(e) => onAcChange(e.target.value)}
          >
            {ac === "" ? <option value="">—</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>
          <select
            id={`at-${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={at}
            disabled={busy}
            onChange={(e) => {
              setAt(e.target.value)
              setMessage(null)
            }}
          >
            <option value="">—</option>
            {atSelectOptions.map((type) => (
              <option key={type} value={type}>
                {type}
              </option>
            ))}
          </select>
          <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 || 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}
          onClick={onReset}
        >
          Reset
        </button>
        <span className="text-[10px] text-muted-foreground">
          Saving locks the row and remaps PIB from AC/AT.
        </span>
      </div>
      {error ? <p className="text-xs text-destructive">{error}</p> : null}
      {message ? <p className="text-xs text-muted-foreground">{message}</p> : null}
    </div>
  )
}
