"use client"

import { Suspense, useEffect, useState } from "react"
import { useRouter, useSearchParams } from "next/navigation"
import Link from "next/link"
import { ArrowLeft, ExternalLink, Plus, Trash2 } from "lucide-react"

import { purchaseOrdersApi } from "@/lib/api/purchase-orders"
import { requisitionsApi } from "@/lib/api/requisitions"
import { rfqsApi } from "@/lib/api/rfqs"
import { vendorsApi } from "@/lib/api/vendors"
import { warehousesApi } from "@/lib/api/warehouses"
import { itemsApi } from "@/lib/api/items"
import { uomsApi } from "@/lib/api/uoms"
import { baseUomLabel } from "@/lib/uom-label"
import { errorMessage } from "@/lib/error-map"
import { validatePoLine } from "@/lib/validations/procurement"
import { cn } from "@/lib/utils"
import { generateVendorCode } from "@/lib/vendor-code"
import { CreatePoLineInput } from "@/types/procurement"
import { ItemListItem, Uom, Vendor, Warehouse } from "@/types/master-data"

import { Button, buttonVariants } from "@/components/ui/button"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Field, FieldError, FieldGroup, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Skeleton } from "@/components/ui/skeleton"
import { toast } from "@/components/ui/toast"

interface DraftLine {
  key: string
  itemId: number | null
  warehouseId: number | null
  qty: string
  unitPrice: string
  tax: string
}

let keySeq = 0
function newKey() {
  keySeq += 1
  return `poline-${keySeq}`
}

// Tax is still not entered at PO creation — it's captured at GRN receipt (with discount/VAT
// there) and stays off this form, though it remains on the payload since the backend line
// DTO still requires it. Unit price *is* entered here; a PO prefilled from an RFQ starts
// from its negotiated price (below) but stays editable.
function emptyLine(): DraftLine {
  return { key: newKey(), itemId: null, warehouseId: null, qty: "", unitPrice: "0", tax: "0" }
}

function NewPurchaseOrderContent() {
  const router = useRouter()
  const searchParams = useSearchParams()
  const requisitionId = Number(searchParams.get("requisitionId")) || null
  const rfqId = Number(searchParams.get("rfqId")) || null
  const rfqVendorId = Number(searchParams.get("vendorId")) || null

  const [items, setItems] = useState<ItemListItem[] | null>(null)
  const [uoms, setUoms] = useState<Uom[] | null>(null)
  const [warehouses, setWarehouses] = useState<Warehouse[] | null>(null)
  const [vendors, setVendors] = useState<Vendor[] | null>(null)
  const [prefillLoading, setPrefillLoading] = useState(!!requisitionId || !!rfqId)
  const [loadError, setLoadError] = useState<string | null>(null)

  const [vendorId, setVendorId] = useState<number | null>(rfqVendorId)
  const [lines, setLines] = useState<DraftLine[]>([emptyLine()])

  const [headerError, setHeaderError] = useState<string | null>(null)
  const [lineErrors, setLineErrors] = useState<Record<string, Record<string, string>>>({})
  const [submitError, setSubmitError] = useState<string | null>(null)
  const [submitting, setSubmitting] = useState(false)

  const [vendorDialogOpen, setVendorDialogOpen] = useState(false)
  const [vName, setVName] = useState("")
  const [vTerms, setVTerms] = useState("")
  const [vTaxReg, setVTaxReg] = useState("")
  const [vCurrency, setVCurrency] = useState("LKR")
  const [vErrors, setVErrors] = useState<Record<string, string>>({})
  const [vSubmitting, setVSubmitting] = useState(false)

  const generatedVendorCode = vName.trim() ? generateVendorCode(vName, (vendors ?? []).map((v) => v.code)) : ""

  function loadItems() {
    return itemsApi.list({ pageSize: 200, status: "Active" }).then((it) => setItems(it.items))
  }
  function loadVendors() {
    return vendorsApi.list({ pageSize: 200, status: "Active" }).then((ve) => setVendors(ve.items))
  }

  useEffect(() => {
    Promise.all([
      loadItems(),
      uomsApi.list().then((uo) => setUoms(uo.items)),
      warehousesApi.list().then((wh) => setWarehouses(wh.items)),
      loadVendors(),
    ]).catch((err) => setLoadError(errorMessage(err)))
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  // A new item is created on the standalone item builder (too many fields for a modal here),
  // typically in another tab — refetch on refocus so it shows up in the line pickers without
  // the user having to reload this page and lose their draft.
  useEffect(() => {
    function onFocus() {
      loadItems().catch(() => {})
    }
    window.addEventListener("focus", onFocus)
    return () => window.removeEventListener("focus", onFocus)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  function resetVendorForm() {
    setVName("")
    setVTerms("")
    setVTaxReg("")
    setVCurrency("LKR")
    setVErrors({})
  }

  async function handleCreateVendor() {
    const nextErrors: Record<string, string> = {}
    if (!vName.trim()) nextErrors.name = "Vendor name is required"
    if (!vCurrency.trim()) nextErrors.currency = "Currency is required"
    setVErrors(nextErrors)
    if (Object.keys(nextErrors).length > 0) return

    setVSubmitting(true)
    try {
      const result = await vendorsApi.create({
        code: generatedVendorCode,
        name: vName,
        terms: vTerms || null,
        taxReg: vTaxReg || null,
        currency: vCurrency,
      })
      await loadVendors()
      setVendorId(result.data.vendorId)
      toast.success("Vendor created", `${result.data.code} — ${result.data.name}`)
      setVendorDialogOpen(false)
      resetVendorForm()
    } catch (err) {
      // A 409 here means another creation raced ours for the same generated code — the
      // proactive de-dupe above only knows about vendors loaded when the dialog opened.
      toast.error("Could not create vendor", errorMessage(err))
    } finally {
      setVSubmitting(false)
    }
  }

  useEffect(() => {
    if (requisitionId) {
      requisitionsApi
        .get(requisitionId)
        .then((req) => {
          setLines(
            req.lines.map(
              (l): DraftLine => ({
                key: newKey(),
                itemId: l.itemId,
                warehouseId: null,
                qty: String(l.qty),
                unitPrice: "0",
                tax: "0",
              })
            )
          )
        })
        .catch((err) => setHeaderError(errorMessage(err)))
        .finally(() => setPrefillLoading(false))
      return
    }

    if (rfqId && rfqVendorId) {
      Promise.all([rfqsApi.get(rfqId), rfqsApi.comparison(rfqId)])
        .then(([rfq, comparison]) => {
          setVendorId(rfqVendorId)
          setLines(
            rfq.lines.map((l): DraftLine => {
              const cell = comparison.rows
                .find((row) => row.itemId === l.itemId)
                ?.quotes.find((q) => q.vendorId === rfqVendorId)
              return {
                key: newKey(),
                itemId: l.itemId,
                warehouseId: null,
                qty: String(l.qty),
                unitPrice: cell ? String(cell.unitPrice) : "0",
                tax: "0",
              }
            })
          )
        })
        .catch((err) => setHeaderError(errorMessage(err)))
        .finally(() => setPrefillLoading(false))
      return
    }

    setPrefillLoading(false)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [requisitionId, rfqId, rfqVendorId])

  function updateLine(key: string, patch: Partial<DraftLine>) {
    setLines((prev) => prev.map((l) => (l.key === key ? { ...l, ...patch } : l)))
  }

  function removeLine(key: string) {
    setLines((prev) => prev.filter((l) => l.key !== key))
  }

  function itemFor(itemId: number | null) {
    return items?.find((i) => i.itemId === itemId) ?? null
  }

  async function handleSubmit(saveAsDraft: boolean) {
    setHeaderError(null)
    setSubmitError(null)

    if (!vendorId) {
      setHeaderError("Select a vendor.")
      return
    }
    if (lines.length === 0) {
      setSubmitError("Add at least one line.")
      return
    }

    const nextLineErrors: Record<string, Record<string, string>> = {}
    for (const line of lines) {
      const errors = validatePoLine({
        itemId: line.itemId,
        warehouseId: line.warehouseId,
        qty: line.qty,
        unitPrice: line.unitPrice,
        tax: line.tax,
      })
      if (Object.keys(errors).length > 0) nextLineErrors[line.key] = errors
    }
    setLineErrors(nextLineErrors)
    if (Object.keys(nextLineErrors).length > 0) {
      setSubmitError("Fix the highlighted lines before submitting.")
      return
    }

    const payloadLines: CreatePoLineInput[] = lines.map((l) => ({
      itemId: l.itemId as number,
      warehouseId: l.warehouseId as number,
      qty: Number(l.qty),
      unitPrice: Number(l.unitPrice),
      tax: Number(l.tax),
    }))

    setSubmitting(true)
    try {
      const { data: po } = await purchaseOrdersApi.create({
        vendorId,
        requisitionId: requisitionId ?? (rfqId ? undefined : null),
        lines: payloadLines,
        saveAsDraft,
      })
      toast.success(
        "Purchase order created",
        saveAsDraft ? `${po.docNo} — saved as draft.` : `${po.docNo} — auto-approved (FR-PROC-04).`
      )
      router.push(`/dashboard/procurement/purchase-orders/${po.poId}`)
    } catch (err) {
      setSubmitError(errorMessage(err))
      toast.error("Could not create purchase order", errorMessage(err))
    } finally {
      setSubmitting(false)
    }
  }

  const loading = !items || !uoms || !warehouses || !vendors || prefillLoading

  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-3">
        <div>
          <h1 className="text-2xl font-bold text-foreground">New Purchase Order</h1>
          <p className="text-base text-muted-foreground">Auto-approved on creation; freely editable while open (FR-PROC-03..05).</p>
        </div>
      </div>

      {loadError && (
        <div className="rounded-lg border border-destructive/30 bg-destructive/5 p-5 text-base text-destructive">{loadError}</div>
      )}

      {loading && !loadError && <Skeleton className="h-24 w-full" />}

      {!loading && (
        <>
          <div className="grid grid-cols-1 gap-4 sm:grid-cols-4">
            <div className="flex flex-col gap-2 sm:col-span-1">
              <Label className="text-base">Vendor</Label>
              <div className="flex items-center gap-2">
                <Select<number | null>
                  value={vendorId}
                  onValueChange={setVendorId}
                  items={(vendors ?? []).map((v) => ({ label: `${v.code} — ${v.name}`, value: v.vendorId }))}
                >
                  <SelectTrigger className="h-12! w-full text-base">
                    <SelectValue placeholder="Select vendor" />
                  </SelectTrigger>
                  <SelectContent>
                    {(vendors ?? []).map((v) => (
                      <SelectItem key={v.vendorId} value={v.vendorId} className="text-base">
                        {v.code} — {v.name}
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>

                <Dialog open={vendorDialogOpen} onOpenChange={(o) => { setVendorDialogOpen(o); if (!o) resetVendorForm() }}>
                  <DialogTrigger
                    render={<Button type="button" variant="outline" size="icon-lg" aria-label="New vendor" title="New vendor" />}
                  >
                    <Plus className="size-5" />
                  </DialogTrigger>
                  <DialogContent className="sm:max-w-md">
                    <DialogHeader className="items-center text-center">
                      <DialogTitle>New vendor</DialogTitle>
                      <DialogDescription>Create a supplier record without leaving this PO. Its code is generated from the name.</DialogDescription>
                    </DialogHeader>
                    <FieldGroup>
                      <Field data-invalid={!!vErrors.name}>
                        <FieldLabel htmlFor="po-v-name">Name</FieldLabel>
                        <Input id="po-v-name" value={vName} onChange={(e) => setVName(e.target.value)} placeholder="Lanka Steel Traders (Pvt) Ltd" aria-invalid={!!vErrors.name} />
                        <FieldError errors={[vErrors.name ? { message: vErrors.name } : undefined]} />
                      </Field>
                      <Field>
                        <FieldLabel htmlFor="po-v-code">Code (auto-generated)</FieldLabel>
                        <Input id="po-v-code" value={generatedVendorCode} readOnly disabled placeholder="Enter a name to generate a code" className="text-muted-foreground" />
                      </Field>
                      <Field>
                        <FieldLabel htmlFor="po-v-terms">Payment terms (optional)</FieldLabel>
                        <Input id="po-v-terms" value={vTerms} onChange={(e) => setVTerms(e.target.value)} placeholder="NET30" />
                      </Field>
                      <Field>
                        <FieldLabel htmlFor="po-v-taxreg">Tax registration (optional)</FieldLabel>
                        <Input id="po-v-taxreg" value={vTaxReg} onChange={(e) => setVTaxReg(e.target.value)} placeholder="134567890-7000" />
                      </Field>
                      <Field data-invalid={!!vErrors.currency}>
                        <FieldLabel htmlFor="po-v-currency">Currency</FieldLabel>
                        <Input id="po-v-currency" value={vCurrency} onChange={(e) => setVCurrency(e.target.value)} placeholder="LKR" maxLength={3} aria-invalid={!!vErrors.currency} />
                        <FieldError errors={[vErrors.currency ? { message: vErrors.currency } : undefined]} />
                      </Field>
                    </FieldGroup>
                    <div className="flex flex-col-reverse gap-3 pt-2 sm:flex-row sm:justify-center">
                      <Button variant="outline" className="w-full sm:w-auto sm:min-w-36" onClick={() => setVendorDialogOpen(false)} disabled={vSubmitting}>
                        Cancel
                      </Button>
                      <Button className="w-full sm:w-auto sm:min-w-36" onClick={handleCreateVendor} disabled={vSubmitting}>
                        {vSubmitting ? "Creating…" : "Create"}
                      </Button>
                    </div>
                  </DialogContent>
                </Dialog>
              </div>
            </div>
            {requisitionId && (
              <div className="flex flex-col justify-end pb-2.5 text-sm text-muted-foreground">From Requisition #{requisitionId}</div>
            )}
            {rfqId && <div className="flex flex-col justify-end pb-2.5 text-sm text-muted-foreground">From RFQ #{rfqId}</div>}
          </div>

          {headerError && (
            <div className="rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-base text-destructive">{headerError}</div>
          )}

          <div className="flex flex-col gap-3">
            <div className="flex items-center justify-between">
              <h2 className="text-base font-semibold text-foreground">Lines</h2>
              <div className="flex items-center gap-2">
                <Link
                  href="/dashboard/products/new"
                  target="_blank"
                  rel="noopener noreferrer"
                  className={cn(buttonVariants({ variant: "outline" }))}
                  title="Opens in a new tab — the item list here refreshes when you come back"
                >
                  <ExternalLink className="size-5" />
                  New item
                </Link>
                <Button type="button" variant="outline" onClick={() => setLines((prev) => [...prev, emptyLine()])}>
                  <Plus className="size-5" />
                  Add line
                </Button>
              </div>
            </div>

            {lines.length > 0 && (
              <div className="overflow-x-auto">
                <Table className="table-fixed text-base">
                  <TableHeader>
                    <TableRow>
                      <TableHead className="h-12 w-32 px-3 text-sm">Item</TableHead>
                      <TableHead className="h-12 w-16 px-3 text-sm">UOM</TableHead>
                      <TableHead className="h-12 w-20 px-3 text-sm">Warehouse</TableHead>
                      <TableHead className="h-12 w-24 px-3 text-sm">Qty</TableHead>
                      <TableHead className="h-12 w-28 px-3 text-sm">Unit price</TableHead>
                      <TableHead className="h-12 w-10 px-3" />
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {lines.map((line) => {
                      const errors = lineErrors[line.key] ?? {}
                      const item = itemFor(line.itemId)
                      return (
                        <TableRow key={line.key}>
                          <TableCell className="px-3 py-3 align-top">
                            {requisitionId || rfqId ? (
                              <div className="flex h-11 items-center truncate text-base" title={item ? `${item.sku} — ${item.name}` : undefined}>{item ? `${item.sku} — ${item.name}` : `Item #${line.itemId}`}</div>
                            ) : (
                              <>
                                <Select<number | null> value={line.itemId} onValueChange={(v) => updateLine(line.key, { itemId: v })}>
                                  <SelectTrigger
                                    className="h-11! w-full text-base"
                                    aria-invalid={!!errors.itemId}
                                    title={item ? `${item.sku} — ${item.name}` : undefined}
                                  >
                                    <SelectValue placeholder="Select item" />
                                  </SelectTrigger>
                                  <SelectContent>
                                    {(items ?? []).map((i) => (
                                      <SelectItem key={i.itemId} value={i.itemId} className="text-base">
                                        {i.sku} — {i.name}
                                      </SelectItem>
                                    ))}
                                  </SelectContent>
                                </Select>
                                <FieldError errors={[errors.itemId ? { message: errors.itemId } : undefined]} />
                              </>
                            )}
                          </TableCell>
                          <TableCell className="px-3 py-3 align-top">
                            <div className="flex h-11 items-center text-base text-muted-foreground">
                              {baseUomLabel(items ?? [], uoms ?? [], line.itemId)}
                            </div>
                          </TableCell>
                          <TableCell className="px-3 py-3 align-top">
                            <Select<number | null> value={line.warehouseId} onValueChange={(v) => updateLine(line.key, { warehouseId: v })}>
                              <SelectTrigger className="h-11! w-full text-base" aria-invalid={!!errors.warehouseId}>
                                <SelectValue placeholder="Warehouse" />
                              </SelectTrigger>
                              <SelectContent>
                                {(warehouses ?? []).map((w) => (
                                  <SelectItem key={w.warehouseId} value={w.warehouseId} className="text-base">
                                    {w.code}
                                  </SelectItem>
                                ))}
                              </SelectContent>
                            </Select>
                            <FieldError errors={[errors.warehouseId ? { message: errors.warehouseId } : undefined]} />
                          </TableCell>
                          <TableCell className="px-3 py-3 align-top">
                            <Input
                              type="number"
                              min="0"
                              step="any"
                              value={line.qty}
                              aria-invalid={!!errors.qty}
                              onChange={(e) => updateLine(line.key, { qty: e.target.value })}
                              className="h-11 text-base"
                            />
                            <FieldError errors={[errors.qty ? { message: errors.qty } : undefined]} />
                          </TableCell>
                          <TableCell className="px-3 py-3 align-top">
                            <Input
                              type="number"
                              min="0"
                              step="any"
                              value={line.unitPrice}
                              aria-invalid={!!errors.unitPrice}
                              onChange={(e) => updateLine(line.key, { unitPrice: e.target.value })}
                              className="h-11 text-base"
                            />
                            <FieldError errors={[errors.unitPrice ? { message: errors.unitPrice } : undefined]} />
                          </TableCell>
                          <TableCell className="px-3 py-3 align-top">
                            <Button type="button" variant="ghost" size="icon" onClick={() => removeLine(line.key)} aria-label="Remove line">
                              <Trash2 className="size-5" />
                            </Button>
                          </TableCell>
                        </TableRow>
                      )
                    })}
                  </TableBody>
                </Table>
              </div>
            )}
          </div>

          {submitError && (
            <div className="rounded-lg border border-destructive/30 bg-destructive/5 p-4 text-base text-destructive">{submitError}</div>
          )}

          <div className="flex justify-end gap-3">
            <Link href="/dashboard/procurement/purchase-orders" className={cn(buttonVariants({ variant: "outline", size: "lg" }))}>
              Cancel
            </Link>
            <Button size="lg" type="button" variant="outline" onClick={() => handleSubmit(true)} disabled={submitting}>
              {submitting ? "Saving…" : "Save as draft"}
            </Button>
            <Button size="lg" type="button" onClick={() => handleSubmit(false)} disabled={submitting}>
              {submitting ? "Creating…" : "Create & submit"}
            </Button>
          </div>
        </>
      )}
    </div>
  )
}

export default function NewPurchaseOrderPage() {
  return (
    <Suspense fallback={<Skeleton className="h-48 w-full" />}>
      <NewPurchaseOrderContent />
    </Suspense>
  )
}
