"use client"

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

import { grnsApi } from "@/lib/api/grns"
import { warehousesApi } from "@/lib/api/warehouses"
import { itemsApi } from "@/lib/api/items"
import { uomsApi } from "@/lib/api/uoms"
import { errorMessage } from "@/lib/error-map"
import { validateLine, splitSerials } from "@/lib/validations/grn"
import { cn } from "@/lib/utils"
import { CreateGrnLineInput, Grn, HoldStatus } from "@/types/grn"
import { Bin, ItemListItem, Uom, Warehouse } from "@/types/master-data"

import { Button, buttonVariants } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { FieldError } from "@/components/ui/field"
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
  poLineId: number | null
  itemId: number | null
  uomId: number | null
  binId: number | null
  qty: string
  unitCost: string
  holdStatus: HoldStatus
  batchNo: string
  expiryDate: string
  serialNumbersText: string
}

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

function emptyLine(): DraftLine {
  return {
    key: newKey(),
    poLineId: null,
    itemId: null,
    uomId: null,
    binId: null,
    qty: "",
    unitCost: "",
    holdStatus: "Available",
    batchNo: "",
    expiryDate: "",
    serialNumbersText: "",
  }
}

export default function EditGrnPage() {
  const params = useParams<{ id: string }>()
  const router = useRouter()
  const grnId = Number(params.id)

  const [grn, setGrn] = useState<Grn | null>(null)
  const [warehouses, setWarehouses] = useState<Warehouse[] | null>(null)
  const [items, setItems] = useState<ItemListItem[] | null>(null)
  const [uoms, setUoms] = useState<Uom[] | null>(null)
  const [bins, setBins] = useState<Bin[]>([])
  const [loadError, setLoadError] = useState<string | null>(null)

  const [warehouseId, setWarehouseId] = useState<number | null>(null)
  const [lines, setLines] = useState<DraftLine[]>([])

  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)

  useEffect(() => {
    if (!Number.isFinite(grnId)) return
    Promise.all([
      grnsApi.get(grnId),
      warehousesApi.list(),
      itemsApi.list({ pageSize: 200, status: "Active" }),
      uomsApi.list(),
    ])
      .then(([g, wh, it, uo]) => {
        if (g.status !== "Draft") {
          setLoadError(`${g.docNo} is ${g.status.toLowerCase()} and can no longer be edited.`)
          setGrn(g)
          return
        }
        setGrn(g)
        setWarehouses(wh.items)
        setItems(it.items)
        setUoms(uo.items)
        setWarehouseId(g.warehouseId)
        setLines(
          g.lines.map(
            (l): DraftLine => ({
              key: newKey(),
              poLineId: l.poLineId,
              itemId: l.itemId,
              uomId: l.uomId,
              binId: l.binId,
              qty: String(l.qty),
              unitCost: String(l.unitCost),
              holdStatus: l.holdStatus,
              batchNo: "",
              expiryDate: "",
              serialNumbersText: "",
            })
          )
        )
      })
      .catch((err) => setLoadError(errorMessage(err)))
  }, [grnId])

  useEffect(() => {
    if (!warehouseId) {
      setBins([])
      return
    }
    warehousesApi.listBins(warehouseId).then((r) => setBins(r.items)).catch(() => setBins([]))
  }, [warehouseId])

  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() {
    if (!grn) return
    setSubmitError(null)
    setHeaderError(null)

    if (!warehouseId) {
      setHeaderError("Select a warehouse.")
      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 = validateLine({
        itemId: line.itemId,
        uomId: line.uomId,
        qty: line.qty,
        unitCost: line.unitCost,
        trackingMode: itemFor(line.itemId)?.trackingMode ?? null,
        batchNo: line.batchNo,
        serialNumbersText: line.serialNumbersText,
      })
      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: CreateGrnLineInput[] = lines.map((l) => {
      const trackingMode = itemFor(l.itemId)?.trackingMode ?? "None"
      return {
        poLineId: l.poLineId,
        itemId: l.itemId as number,
        uomId: l.uomId as number,
        binId: l.binId,
        qty: Number(l.qty),
        unitCost: Number(l.unitCost),
        holdStatus: l.holdStatus,
        batch: trackingMode === "Batch" ? { batchNo: l.batchNo.trim(), expiryDate: l.expiryDate || null } : null,
        serialNumbers: trackingMode === "Serial" ? splitSerials(l.serialNumbersText) : null,
      }
    })

    setSubmitting(true)
    try {
      const updated = await grnsApi.update(grn.grnId, {
        poId: grn.poId,
        vendorId: grn.vendorId,
        warehouseId: warehouseId as number,
        lines: payloadLines,
      })
      toast.success("GRN updated", `${updated.docNo} saved.`)
      router.push(`/dashboard/receiving/grn/${updated.grnId}`)
    } catch (err) {
      setSubmitError(errorMessage(err))
      toast.error("Could not update GRN", errorMessage(err))
    } finally {
      setSubmitting(false)
    }
  }

  if (loadError) {
    return (
      <div className="flex flex-col gap-6">
        <div className="flex items-center gap-3">
          <Link
            href={grn ? `/dashboard/receiving/grn/${grn.grnId}` : "/dashboard/receiving/grn"}
            className={cn(buttonVariants({ variant: "ghost", size: "icon-lg" }))}
          >
            <ArrowLeft className="size-5" />
          </Link>
          <h1 className="text-2xl font-bold text-foreground">Edit GRN</h1>
        </div>
        <div className="rounded-lg border border-destructive/30 bg-destructive/5 p-5 text-base text-destructive">{loadError}</div>
      </div>
    )
  }

  const loading = !grn || !warehouses || !items || !uoms

  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-3">
        <Link
          href={grn ? `/dashboard/receiving/grn/${grn.grnId}` : "/dashboard/receiving/grn"}
          className={cn(buttonVariants({ variant: "ghost", size: "icon-lg" }))}
        >
          <ArrowLeft className="size-5" />
        </Link>
        <div>
          <h1 className="text-2xl font-bold text-foreground">Edit {grn?.docNo ?? "GRN"}</h1>
          <p className="text-base text-muted-foreground">Only Draft GRNs can be edited — confirming posts stock layers permanently.</p>
        </div>
      </div>

      {loading && <Skeleton className="h-12 w-full" />}

      {!loading && (
        <>
          <div className="grid grid-cols-1 gap-4 sm:grid-cols-3">
            <div className="flex flex-col gap-2">
              <Label className="text-base">Warehouse</Label>
              <Select<number | null> value={warehouseId} onValueChange={(v) => setWarehouseId(v)}>
                <SelectTrigger className="h-12! w-full text-base">
                  <SelectValue placeholder="Select warehouse" />
                </SelectTrigger>
                <SelectContent>
                  {(warehouses ?? []).map((w) => (
                    <SelectItem key={w.warehouseId} value={w.warehouseId} className="text-base">
                      {w.code} — {w.name}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </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>
              <Button type="button" variant="outline" onClick={() => setLines((prev) => [...prev, emptyLine()])}>
                <Plus className="size-5" />
                Add line
              </Button>
            </div>

            {lines.length > 0 && (
              <Table className="text-base">
                <TableHeader>
                  <TableRow>
                    <TableHead className="h-12 w-56 px-3 text-sm">Item</TableHead>
                    <TableHead className="h-12 w-28 px-3 text-sm">UOM</TableHead>
                    <TableHead className="h-12 w-32 px-3 text-sm">Bin</TableHead>
                    <TableHead className="h-12 w-24 px-3 text-sm">Qty</TableHead>
                    <TableHead className="h-12 w-28 px-3 text-sm">Unit cost</TableHead>
                    <TableHead className="h-12 w-36 px-3 text-sm">Hold status</TableHead>
                    <TableHead className="h-12 w-48 px-3 text-sm">Batch / Serial</TableHead>
                    <TableHead className="h-12 w-10 px-3" />
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {lines.map((line) => {
                    const item = itemFor(line.itemId)
                    const errors = lineErrors[line.key] ?? {}
                    return (
                      <TableRow key={line.key}>
                        <TableCell className="px-3 py-3 align-top">
                          <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}>
                              <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">
                          <Select<number | null> value={line.uomId} onValueChange={(v) => updateLine(line.key, { uomId: v })}>
                            <SelectTrigger className="h-11! w-full text-base" aria-invalid={!!errors.uomId}>
                              <SelectValue placeholder="UOM" />
                            </SelectTrigger>
                            <SelectContent>
                              {(uoms ?? []).map((u) => (
                                <SelectItem key={u.uomId} value={u.uomId} className="text-base">
                                  {u.name}
                                </SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                          <FieldError errors={[errors.uomId ? { message: errors.uomId } : undefined]} />
                        </TableCell>
                        <TableCell className="px-3 py-3 align-top">
                          <Select<number | null> value={line.binId} onValueChange={(v) => updateLine(line.key, { binId: v })}>
                            <SelectTrigger className="h-11! w-full text-base">
                              <SelectValue placeholder="None" />
                            </SelectTrigger>
                            <SelectContent>
                              {bins.map((b) => (
                                <SelectItem key={b.binId} value={b.binId} className="text-base">
                                  {b.code}
                                </SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                        </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.unitCost}
                            aria-invalid={!!errors.unitCost}
                            onChange={(e) => updateLine(line.key, { unitCost: e.target.value })}
                            className="h-11 text-base"
                          />
                          <FieldError errors={[errors.unitCost ? { message: errors.unitCost } : undefined]} />
                        </TableCell>
                        <TableCell className="px-3 py-3 align-top">
                          <Select<HoldStatus> value={line.holdStatus} onValueChange={(v) => v && updateLine(line.key, { holdStatus: v })}>
                            <SelectTrigger className="h-11! w-full text-base">
                              <SelectValue />
                            </SelectTrigger>
                            <SelectContent>
                              <SelectItem value="Available" className="text-base">Available</SelectItem>
                              <SelectItem value="OnHold" className="text-base">On hold (inspection)</SelectItem>
                            </SelectContent>
                          </Select>
                        </TableCell>
                        <TableCell className="px-3 py-3 align-top">
                          {item?.trackingMode === "Batch" && (
                            <div className="flex flex-col gap-1.5">
                              <Input
                                placeholder="Batch no."
                                value={line.batchNo}
                                aria-invalid={!!errors.batchNo}
                                onChange={(e) => updateLine(line.key, { batchNo: e.target.value })}
                                className="h-9 text-sm"
                              />
                              <Input
                                type="date"
                                value={line.expiryDate}
                                onChange={(e) => updateLine(line.key, { expiryDate: e.target.value })}
                                className="h-9 text-sm"
                              />
                              <FieldError errors={[errors.batchNo ? { message: errors.batchNo } : undefined]} />
                            </div>
                          )}
                          {item?.trackingMode === "Serial" && (
                            <div className="flex flex-col gap-1.5">
                              <textarea
                                placeholder="One serial per line"
                                value={line.serialNumbersText}
                                aria-invalid={!!errors.serialNumbers}
                                onChange={(e) => updateLine(line.key, { serialNumbersText: e.target.value })}
                                className="min-h-16 w-full rounded-lg border border-input bg-transparent p-2 text-sm outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50"
                              />
                              <FieldError errors={[errors.serialNumbers ? { message: errors.serialNumbers } : undefined]} />
                            </div>
                          )}
                          {(!item || item.trackingMode === "None") && (
                            <span className="text-sm text-muted-foreground">—</span>
                          )}
                        </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>

          {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/receiving/grn/${grnId}`}
              className={cn(buttonVariants({ variant: "outline", size: "lg" }))}
            >
              Cancel
            </Link>
            <Button size="lg" type="button" onClick={handleSubmit} disabled={submitting}>
              {submitting ? "Saving…" : "Save changes"}
            </Button>
          </div>
        </>
      )}
    </div>
  )
}
