"use client"

import { useCallback, useEffect, useMemo, useState } from "react"
import { useParams, useRouter } from "next/navigation"
import { ReactFlow, Background, Controls, MiniMap, type Edge, type Node, type NodeMouseHandler } from "@xyflow/react"
import "@xyflow/react/dist/style.css"
import { useTheme } from "next-themes"
import { ArrowLeft, RotateCcw } from "lucide-react"

import { cn } from "@/lib/utils"
import { productionRunsApi } from "@/lib/api/production-runs"
import { itemsApi } from "@/lib/api/items"
import { uomsApi } from "@/lib/api/uoms"
import { warehousesApi } from "@/lib/api/warehouses"
import { reasonCodesApi } from "@/lib/api/reason-codes"
import { errorMessage } from "@/lib/error-map"
import { ProductionRunGraph, ProductionRunStatus, RunStage, StageSummary } from "@/types/production"
import { ItemListItem, Uom, Warehouse } from "@/types/master-data"
import { ReasonCode } from "@/types/stock"
import { STAGE_STATUS_COLOR } from "@/lib/production-status-colors"
import {
  RunHeaderNodeComponent,
  RunStageNodeComponent,
  type RunHeaderData,
  type RunStageData,
} from "@/components/production/RunStageNode"
import { StageProgressStrip, StageStatusLegend } from "@/components/production/stage-progress-strip"

import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Skeleton } from "@/components/ui/skeleton"
import { StageDrawer } from "./StageDrawer"
import { RunActions } from "./RunActions"

function runStatusBadgeClass(status: ProductionRunStatus) {
  if (status === "Completed") return "bg-success/10 text-success"
  if (status === "Cancelled") return "bg-destructive/10 text-destructive"
  return "bg-info/10 text-info"
}

const nodeTypes = { runHeader: RunHeaderNodeComponent, runStage: RunStageNodeComponent }

/**
 * Where the run header box sits relative to the stages.
 *
 * Stage positions come from the run's own `posX`/`posY` — copied from the template at creation
 * (FR-MFG-06), so the canvas matches what was drawn in the builder. The header is placed to the
 * left of the leftmost stage rather than at a fixed origin, because those coordinates are
 * arbitrary and could otherwise put the header on top of a stage.
 */
const HEADER_GAP_X = 240

function buildFlow(run: ProductionRunGraph): { nodes: Node[]; edges: Edge[] } {
  const minX = run.stages.length > 0 ? Math.min(...run.stages.map((s) => s.posX)) : 0
  const minY = run.stages.length > 0 ? Math.min(...run.stages.map((s) => s.posY)) : 0

  const nodes: Node[] = [
    {
      id: "header",
      type: "runHeader",
      position: { x: minX - HEADER_GAP_X, y: minY },
      data: { docNo: run.docNo, templateName: run.templateName, status: run.status } satisfies RunHeaderData,
      draggable: false,
    },
  ]

  // The stage the operator is expected to act on: the furthest-along actionable one, so a run
  // mid-flight highlights the stage in progress rather than the first thing still Waiting.
  const actionable = ["InProgress", "Done", "Ready"] as const
  const activeId =
    run.status === "InProgress"
      ? actionable.reduce<number | null>(
          (found, status) => found ?? run.stages.find((s) => s.status === status)?.runStageId ?? null,
          null
        )
      : null

  for (const stage of run.stages) {
    const upstream = stage.inputs.filter((i) => i.source === "Upstream")
    nodes.push({
      id: String(stage.runStageId),
      type: "runStage",
      position: { x: stage.posX, y: stage.posY },
      data: {
        name: stage.name,
        roleLabel: stage.roleLabel,
        state: stage.status,
        isTerminal: stage.isTerminal,
        isEntry: stage.isEntry,
        estimatedMinutes: stage.estimatedMinutes,
        actualMinutes: stage.actualMinutes,
        actualStartAt: stage.actualStartAt,
        intake:
          upstream.length === 0
            ? null
            : {
                delivered: upstream.reduce((sum, i) => sum + i.deliveredQty, 0),
                planned: upstream.reduce((sum, i) => sum + i.plannedQty, 0),
              },
        availableToTransfer: stage.outputs.reduce((sum, o) => sum + o.availableToTransfer, 0),
        isActive: stage.runStageId === activeId,
      } satisfies RunStageData,
      draggable: false,
    })
  }

  const edges: Edge[] = run.edges.map((e) => {
    const parent = run.stages.find((s) => s.runStageId === e.parentRunStageId)
    return {
      id: `e${e.runEdgeId}`,
      source: String(e.parentRunStageId),
      target: String(e.childRunStageId),
      animated: parent?.status === "InProgress",
    }
  })

  // Entry stages hang off the run header so the line reads left to right from the run itself.
  for (const stage of run.stages.filter((s) => s.isEntry)) {
    edges.push({ id: `eh-${stage.runStageId}`, source: "header", target: String(stage.runStageId) })
  }

  return { nodes, edges }
}

export default function ProductionRunDetailPage() {
  const params = useParams<{ id: string }>()
  const router = useRouter()
  const { resolvedTheme } = useTheme()
  const runId = Number(params.id)

  const [run, setRun] = useState<ProductionRunGraph | null>(null)
  const [loadError, setLoadError] = useState<string | null>(null)
  const [selectedStageId, setSelectedStageId] = useState<number | null>(null)

  const [items, setItems] = useState<ItemListItem[]>([])
  const [uoms, setUoms] = useState<Uom[]>([])
  const [warehouses, setWarehouses] = useState<Warehouse[]>([])
  const [reasonCodes, setReasonCodes] = useState<ReasonCode[]>([])

  // Same hydration-mismatch guard as the other canvas pages: colorMode depends on
  // resolvedTheme, which is unknown on the server and on the client's first paint.
  const [mounted, setMounted] = useState(false)
  useEffect(() => setMounted(true), [])

  const load = useCallback(() => {
    setLoadError(null)
    productionRunsApi
      .get(runId)
      .then(({ data }) => setRun(data))
      .catch((err) => setLoadError(errorMessage(err)))
  }, [runId])

  useEffect(() => {
    if (Number.isFinite(runId)) load()
  }, [runId, load])

  useEffect(() => {
    Promise.all([
      itemsApi.list({ pageSize: 200 }),
      uomsApi.list({ pageSize: 200 }),
      warehousesApi.list({ pageSize: 200 }),
      reasonCodesApi.list("Production", { pageSize: 100 }),
    ])
      .then(([itemRes, uomRes, warehouseRes, reasonRes]) => {
        setItems(itemRes.items)
        setUoms(uomRes.items)
        setWarehouses(warehouseRes.items)
        setReasonCodes(reasonRes.items)
      })
      .catch(() => {
        // Reference data only feeds names and pickers — a failure here degrades labels to ids
        // rather than blocking the run, so it deliberately doesn't set loadError.
      })
  }, [])

  const { nodes, edges } = useMemo(
    () => (run ? buildFlow(run) : { nodes: [] as Node[], edges: [] as Edge[] }),
    [run]
  )

  const stageSummary: StageSummary = useMemo(() => {
    const counts: StageSummary = { waiting: 0, ready: 0, inProgress: 0, done: 0, approved: 0 }
    for (const stage of run?.stages ?? []) {
      if (stage.status === "Waiting") counts.waiting++
      else if (stage.status === "Ready") counts.ready++
      else if (stage.status === "InProgress") counts.inProgress++
      else if (stage.status === "Done") counts.done++
      else counts.approved++
    }
    return counts
  }, [run])

  const selectedStage: RunStage | null =
    run?.stages.find((s) => s.runStageId === selectedStageId) ?? null

  const onNodeClick: NodeMouseHandler = useCallback((_, node) => {
    if (node.type !== "runStage") return
    setSelectedStageId(Number(node.id))
  }, [])

  if (loadError) {
    return (
      <div className="flex flex-col items-center gap-4 rounded-xl border border-dashed py-20 text-center">
        <p className="text-base text-muted-foreground">{loadError}</p>
        <Button variant="outline" onClick={() => router.push("/dashboard/production/runs")}>
          <ArrowLeft className="size-4" />
          Back to runs
        </Button>
      </div>
    )
  }

  if (!run) {
    return (
      <div className="flex flex-col gap-3">
        <Skeleton className="h-10 w-64" />
        <Skeleton className="h-40 w-full rounded-2xl" />
        <Skeleton className="h-[45vh] w-full rounded-2xl" />
      </div>
    )
  }

  const warehouse = warehouses.find((w) => w.warehouseId === run.warehouseId)
  const approvedCount = stageSummary.approved
  const progressPercent = run.stages.length > 0 ? Math.round((approvedCount / run.stages.length) * 100) : 0

  return (
    <div className="flex flex-col gap-6">
      <Button
        variant="ghost"
        className="w-fit px-2 text-muted-foreground hover:text-foreground"
        onClick={() => router.push("/dashboard/production/runs")}
      >
        <ArrowLeft className="size-4" />
        Back to runs
      </Button>

      <div className="rounded-2xl bg-card p-4 shadow-sm ring-1 ring-foreground/10 sm:p-5">
        <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
          <div className="flex min-w-0 flex-col gap-1">
            <div className="flex flex-wrap items-center gap-2">
              <span className="text-lg font-bold text-foreground">{run.docNo}</span>
              <Badge variant="outline" className={cn("h-6 w-fit justify-center border-transparent px-2.5 text-sm", runStatusBadgeClass(run.status))}>
                {run.status === "InProgress" ? "In Progress" : run.status}
              </Badge>
              {run.reworkCount > 0 && (
                <Badge variant="outline" className="h-6 w-fit justify-center gap-1 border-transparent bg-warning/10 px-2.5 text-sm text-warning">
                  <RotateCcw className="size-3.5" />
                  Rework #{run.reworkCount}
                </Badge>
              )}
            </div>
            <p className="text-sm text-muted-foreground">
              {run.templateName}
              {warehouse && ` · ${warehouse.name}`}
              {` · ×${Number(run.scaleFactor.toFixed(6)).toLocaleString()} scale`}
            </p>
          </div>
          <div className="flex shrink-0 flex-col text-left sm:text-right">
            <span className="text-sm font-medium text-foreground">Target {run.targetQty.toLocaleString()}</span>
            <span className="text-sm text-muted-foreground">
              Created {new Date(run.createdAt).toLocaleDateString()}
              {run.completedAt && <> · Completed {new Date(run.completedAt).toLocaleDateString()}</>}
            </span>
          </div>
        </div>

        <StageProgressStrip status={run.status} summary={stageSummary} className="mt-4" />

        <div className="mt-4 flex flex-col gap-3 border-t border-border pt-4 sm:flex-row sm:items-center sm:justify-between">
          <div className="flex-1">
            <div className="flex items-center justify-between text-sm">
              <span className="font-medium text-foreground">
                {progressPercent}% approved
                <span className="text-muted-foreground">
                  {" "}· cost pool {run.costPool.net.toLocaleString(undefined, { minimumFractionDigits: 2 })}
                </span>
              </span>
            </div>
            <div className="mt-1.5 h-2 w-full overflow-hidden rounded-full bg-muted">
              <div
                className="h-full rounded-full transition-all"
                style={{ width: `${progressPercent}%`, backgroundColor: STAGE_STATUS_COLOR.Approved }}
              />
            </div>
          </div>
          <RunActions run={run} items={items} reasonCodes={reasonCodes} onActed={load} />
        </div>
      </div>

      <div className="rounded-2xl bg-card p-4 shadow-sm ring-1 ring-foreground/10">
        <StageStatusLegend />
      </div>

      <p className="text-sm text-muted-foreground">Click a stage to open it.</p>

      <div className="h-[55vh] min-h-96 overflow-hidden rounded-2xl bg-muted ring-1 ring-foreground/10">
        {mounted ? (
          <ReactFlow
            nodes={nodes}
            edges={edges}
            nodeTypes={nodeTypes}
            onNodeClick={onNodeClick}
            nodesDraggable={false}
            nodesConnectable={false}
            elementsSelectable
            panOnDrag
            zoomOnScroll
            colorMode={resolvedTheme === "dark" ? "dark" : "light"}
            fitView
            proOptions={{ hideAttribution: true }}
          >
            <Background />
            <Controls showInteractive={false} />
            <MiniMap pannable zoomable />
          </ReactFlow>
        ) : (
          <Skeleton className="size-full rounded-none" />
        )}
      </div>

      <StageDrawer
        run={run}
        stage={selectedStage}
        items={items}
        uoms={uoms}
        reasonCodes={reasonCodes}
        onClose={() => setSelectedStageId(null)}
        onActed={load}
      />
    </div>
  )
}
