"use client";

import { useRef, useState } from "react";
import {
  Play,
  Loader2,
  FileDown,
  FileUp,
  Eraser,
  Boxes,
  Grid3x3,
  RotateCw,
  Layers,
  FlipHorizontal2,
  FlipVertical2,
} from "lucide-react";
import { useDiagramStore } from "@/store/diagramStore";
import { buildScenarioConfig, validateConfig } from "@/lib/configBuilder";
import { computeDofLedger } from "@/lib/dofLedger";
import { simulate } from "@/lib/api";
import type { EntropykNodeData } from "@/lib/configBuilder";
import type { Node } from "@xyflow/react";
import MultiRunPanel from "@/components/panels/MultiRunPanel";

const FLUIDS = ["R410A", "R134a", "R290", "R744", "R32", "R1234yf", "Water", "Air"];
const BACKENDS = ["CoolProp", "Test"];
const SOLVERS = [
  { value: "newton", label: "Newton" },
  { value: "picard", label: "Picard" },
];

const EXAMPLES = [
  { file: "hx_air_water_4port.json", label: "HX air–water" },
  { file: "chiller_flooded_4port_watercooled.json", label: "Chiller flooded" },
  { file: "chiller_watercooled_r410a.json", label: "Chiller R410A" },
  { file: "chiller_aircooled_r134a.json", label: "Chiller air-cooled" },
  { file: "bphx_evaporator_condenser.json", label: "BPHX cycle" },
  { file: "heatpump_r410a_reversing_valve.json", label: "Heat pump 4-way" },
  { file: "chiller_r134a_exv_orifice.json", label: "EXV orifice" },
  { file: "chiller_r410a_full_physics.json", label: "R410A full physics" },
  { file: "capillary_tube_r134a.json", label: "Capillary smoke" },
];

export default function Toolbar() {
  const {
    nodes,
    edges,
    fluid,
    fluidBackend,
    solverStrategy,
    maxIterations,
    tolerance,
    snapToGrid,
    selectedNodeId,
    setFluid,
    setFluidBackend,
    setSolverStrategy,
    setLastConfig,
    toggleSnapToGrid,
    rotateNode,
    flipNodeH,
    flipNodeV,
    setResult,
    setSimulating,
    simulating,
    loadFromConfig,
    clear,
  } = useDiagramStore();

  const [issues, setIssues] = useState<string[]>([]);
  const [multiOpen, setMultiOpen] = useState(false);
  const [exampleFile, setExampleFile] = useState(EXAMPLES[0].file);
  const fileInputRef = useRef<HTMLInputElement | null>(null);

  const onSimulate = async () => {
    const problems = validateConfig(nodes, edges);
    const ledger = computeDofLedger(nodes as Node<EntropykNodeData>[], edges);
    // Hard block only when over-constrained (no free lunch). Under-constrained
    // diagrams are common while editing — surface as a soft issue after simulate
    // via the status bar; the CLI still hard-fails on non-square systems.
    if (ledger.balance === "over-constrained") {
      problems.push(
        `DoF over-constrained: ${ledger.nEquations} equations > ${ledger.nUnknowns} unknowns. ` +
          `Remove a FIX (quality control, extra outlet closure) or FREE an actuator.`,
      );
    }
    setIssues(problems);
    if (problems.length > 0) return;

    const config = buildScenarioConfig(nodes, edges, {
      fluid,
      fluidBackend,
      solverStrategy,
      maxIterations,
      tolerance,
    });
    setSimulating(true);
    setLastConfig(config);
    setResult(null, null);
    try {
      const resp = await simulate(config);
      if (resp.ok && resp.result) {
        setResult(resp.result, null);
        if (resp.result.dof && resp.result.dof.n_equations !== resp.result.dof.n_unknowns) {
          setIssues([
            `Server DoF: ${resp.result.dof.n_equations} eqs vs ${resp.result.dof.n_unknowns} unk (${resp.result.dof.balance})`,
          ]);
        }
      } else setResult(null, resp.error || "Simulation failed");
    } catch (e) {
      setResult(null, e instanceof Error ? e.message : String(e));
    } finally {
      setSimulating(false);
    }
  };

  const onLoadExample = async () => {
    try {
      const res = await fetch(`/examples/${exampleFile}`);
      if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
      loadFromConfig(await res.json());
      setIssues([]);
    } catch (e) {
      setIssues([`Could not load example: ${e instanceof Error ? e.message : e}`]);
    }
  };

  const onImportJsonFile = async (file: File | undefined) => {
    if (!file) return;
    try {
      const text = await file.text();
      loadFromConfig(JSON.parse(text));
      setIssues([]);
    } catch (e) {
      setIssues([`Could not import JSON: ${e instanceof Error ? e.message : e}`]);
    } finally {
      if (fileInputRef.current) fileInputRef.current.value = "";
    }
  };

  return (
    <header className="flex h-11 items-center gap-2 border-b border-black/40 bg-[var(--bar)] px-3 text-[var(--bar-ink)]">
      <div className="flex items-center gap-2 pr-1">
        <Boxes size={16} className="text-[var(--bar-accent)]" />
        <span className="mono text-[12.5px] font-semibold tracking-[0.14em] text-white">
          ENTROPYK
        </span>
      </div>

      <div className="bar-sep" />

      <BarField label="Fluid">
        <select value={fluid} onChange={(e) => setFluid(e.target.value)} className="bar-select mono">
          {FLUIDS.map((f) => (
            <option key={f} value={f}>
              {f}
            </option>
          ))}
        </select>
      </BarField>
      <BarField label="Props">
        <select
          value={fluidBackend}
          onChange={(e) => setFluidBackend(e.target.value)}
          className="bar-select mono"
        >
          {BACKENDS.map((b) => (
            <option key={b} value={b}>
              {b}
            </option>
          ))}
        </select>
      </BarField>
      <BarField label="Solver">
        <select
          value={solverStrategy}
          onChange={(e) => setSolverStrategy(e.target.value)}
          className="bar-select mono"
        >
          {SOLVERS.map((s) => (
            <option key={s.value} value={s.value}>
              {s.label}
            </option>
          ))}
        </select>
      </BarField>

      <div className="bar-sep" />

      {/* Orientation — icon group, works on the selected part */}
      <div className="flex items-center overflow-hidden rounded-[4px] border border-white/12">
        <button
          onClick={() => selectedNodeId && rotateNode(selectedNodeId, 1)}
          disabled={!selectedNodeId}
          className="bar-icon"
          title="Rotation 90° (R) — sélectionne d’abord une pièce"
        >
          <RotateCw size={13} />
        </button>
        <button
          onClick={() => selectedNodeId && flipNodeH(selectedNodeId)}
          disabled={!selectedNodeId}
          className="bar-icon border-l border-white/12"
          title="Miroir horizontal (H)"
        >
          <FlipHorizontal2 size={13} />
        </button>
        <button
          onClick={() => selectedNodeId && flipNodeV(selectedNodeId)}
          disabled={!selectedNodeId}
          className="bar-icon border-l border-white/12"
          title="Miroir vertical (V)"
        >
          <FlipVertical2 size={13} />
        </button>
        <button
          onClick={toggleSnapToGrid}
          className="bar-icon border-l border-white/12"
          data-active={snapToGrid}
          title="Aimanter à la grille"
        >
          <Grid3x3 size={13} />
        </button>
      </div>

      <div className="flex-1" />

      {issues.length > 0 && (
        <div
          className="mono max-w-[240px] truncate text-[11px] text-amber-300"
          title={issues.join("\n")}
        >
          ⚠ {issues.length} · {issues[0]}
        </div>
      )}

      <select
        value={exampleFile}
        onChange={(e) => setExampleFile(e.target.value)}
        className="bar-select mono max-w-[150px]"
        title="Exemple de scénario"
      >
        {EXAMPLES.map((ex) => (
          <option key={ex.file} value={ex.file}>
            {ex.label}
          </option>
        ))}
      </select>
      <button onClick={onLoadExample} className="bar-btn" title="Charger l’exemple">
        <FileDown size={13} /> Load
      </button>
      <button onClick={() => fileInputRef.current?.click()} className="bar-btn" title="Importer un JSON">
        <FileUp size={13} /> Import
      </button>
      <button onClick={() => setMultiOpen(true)} className="bar-btn" title="Balayage paramétrique parallèle">
        <Layers size={13} /> Multi-run
      </button>
      <button onClick={clear} className="bar-btn" title="Vider la feuille">
        <Eraser size={13} />
      </button>
      <input
        ref={fileInputRef}
        type="file"
        accept="application/json,.json"
        className="hidden"
        onChange={(event) => void onImportJsonFile(event.target.files?.[0])}
      />

      <button
        onClick={onSimulate}
        disabled={simulating}
        className="ml-1 flex items-center gap-1.5 rounded-[4px] bg-[var(--bar-accent)] px-4 py-[7px] text-[12.5px] font-semibold text-[#0c1420] transition-all hover:brightness-110 disabled:opacity-50"
      >
        {simulating ? <Loader2 size={13} className="animate-spin" /> : <Play size={13} />}
        {simulating ? "Solving…" : "Solve"}
      </button>

      {multiOpen && <MultiRunPanel onClose={() => setMultiOpen(false)} />}

      <style jsx>{`
        .bar-sep {
          width: 1px;
          height: 20px;
          background: rgba(255, 255, 255, 0.12);
          margin: 0 4px;
        }
        .bar-btn {
          display: inline-flex;
          align-items: center;
          gap: 5px;
          border-radius: 4px;
          border: 1px solid rgba(255, 255, 255, 0.12);
          background: rgba(255, 255, 255, 0.04);
          padding: 5px 9px;
          font-size: 12px;
          color: var(--bar-ink);
          transition: all 0.12s ease;
        }
        .bar-btn:hover:not(:disabled) {
          background: rgba(255, 255, 255, 0.1);
          color: #fff;
        }
        .bar-icon {
          display: grid;
          place-items: center;
          width: 28px;
          height: 26px;
          color: var(--bar-ink);
          background: rgba(255, 255, 255, 0.04);
          transition: all 0.12s ease;
        }
        .bar-icon:hover:not(:disabled) {
          background: rgba(255, 255, 255, 0.12);
          color: #fff;
        }
        .bar-icon:disabled {
          opacity: 0.35;
          cursor: not-allowed;
        }
        .bar-icon[data-active="true"] {
          background: rgba(94, 176, 255, 0.22);
          color: var(--bar-accent);
        }
        :global(.bar-select) {
          border: 1px solid rgba(255, 255, 255, 0.14);
          background: rgba(255, 255, 255, 0.06);
          border-radius: 4px;
          padding: 4px 6px;
          font-size: 11.5px;
          color: var(--bar-ink);
        }
        :global(.bar-select option) {
          color: var(--ink);
          background: #fff;
        }
      `}</style>
    </header>
  );
}

function BarField({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <label className="flex items-center gap-1.5 leading-none">
      <span className="mono text-[9px] uppercase tracking-[0.1em] text-white/45">{label}</span>
      {children}
    </label>
  );
}
