"use client";

import { useMemo, useState } from "react";
import { Layers, Loader2, Play, Plus, Trash2, X } from "lucide-react";
import { useDiagramStore } from "@/store/diagramStore";
import { buildScenarioConfig, validateConfig } from "@/lib/configBuilder";
import type { EntropykNodeData } from "@/lib/configBuilder";
import type { Node } from "@xyflow/react";
import {
  buildSweepCases,
  defaultSweepsFromDiagram,
  discoverSweepTargets,
  extractKpis,
  runParallel,
  suggestValues,
  type MultiRunResult,
  type SweepSpec,
  type SweepTarget,
} from "@/lib/multiRun";

const GROUP_LABEL: Record<SweepTarget["group"], string> = {
  boundaries: "Conditions limites (eau / air)",
  thermal: "Échangeurs (UA…)",
  machine: "Machine (compresseur / détendeur)",
  global: "Global",
};

export default function MultiRunPanel({ onClose }: { onClose: () => void }) {
  const {
    nodes,
    edges,
    fluid,
    fluidBackend,
    solverStrategy,
    maxIterations,
    tolerance,
  } = useDiagramStore();

  const diagramNodes = nodes as Node<EntropykNodeData>[];
  const targets = useMemo(
    () => discoverSweepTargets(diagramNodes, fluid),
    [diagramNodes, fluid],
  );

  const [sweeps, setSweeps] = useState<SweepSpec[]>(() =>
    defaultSweepsFromDiagram(diagramNodes, fluid),
  );
  const [concurrency, setConcurrency] = useState(4);
  const [running, setRunning] = useState(false);
  const [progress, setProgress] = useState({ done: 0, total: 0 });
  const [results, setResults] = useState<MultiRunResult[] | null>(null);
  const [error, setError] = useState<string | null>(null);

  const baseConfig = useMemo(
    () =>
      buildScenarioConfig(diagramNodes, edges, {
        fluid,
        fluidBackend,
        solverStrategy,
        maxIterations,
        tolerance,
      }),
    [diagramNodes, edges, fluid, fluidBackend, solverStrategy, maxIterations, tolerance],
  );

  const cases = useMemo(() => buildSweepCases(baseConfig, sweeps), [baseConfig, sweeps]);

  const targetsByGroup = useMemo(() => {
    const map = new Map<SweepTarget["group"], SweepTarget[]>();
    for (const t of targets) {
      const list = map.get(t.group) ?? [];
      list.push(t);
      map.set(t.group, list);
    }
    return map;
  }, [targets]);

  const setAxis = (i: number, patch: Partial<SweepSpec>) => {
    setSweeps((all) => all.map((s, j) => (j === i ? { ...s, ...patch } : s)));
  };

  const pickTarget = (i: number, path: string) => {
    const t = targets.find((x) => x.path === path);
    if (!t) {
      setAxis(i, { path });
      return;
    }
    setAxis(i, {
      path: t.path,
      label: t.label,
      kind: t.kind,
      valuesText: suggestValues(t.current, t.paramKey),
    });
  };

  const addAxis = (path?: string) => {
    const t =
      (path ? targets.find((x) => x.path === path) : undefined) ??
      targets.find(
        (x) =>
          x.group === "boundaries" &&
          !sweeps.some((s) => s.path === x.path),
      ) ??
      targets.find((x) => !sweeps.some((s) => s.path === x.path)) ??
      targets[0];
    if (!t) return;
    setSweeps((s) => [
      ...s,
      {
        path: t.path,
        label: t.label,
        kind: t.kind,
        valuesText: suggestValues(t.current, t.paramKey),
      },
    ]);
  };

  const resetToWaterTemps = () => {
    setSweeps(defaultSweepsFromDiagram(diagramNodes, fluid));
    setResults(null);
    setError(null);
  };

  const onRun = async () => {
    setError(null);
    const problems = validateConfig(nodes, edges);
    if (problems.length > 0) {
      setError(problems[0]);
      return;
    }
    if (cases.length === 0) {
      setError("Aucun cas à lancer — renseigne des valeurs sur chaque axe.");
      return;
    }
    if (cases.length > 64) {
      setError(`Trop de cas (${cases.length}). Maximum 64 — réduis les listes de valeurs.`);
      return;
    }
    setRunning(true);
    setProgress({ done: 0, total: cases.length });
    setResults(null);
    try {
      const out = await runParallel(cases, {
        concurrency,
        onProgress: (done, total) => setProgress({ done, total }),
      });
      setResults(out);
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setRunning(false);
    }
  };

  const boundaryCount = targets.filter((t) => t.group === "boundaries").length;

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
      <div className="flex max-h-[90vh] w-full max-w-3xl flex-col overflow-hidden rounded-lg border border-[var(--line)] bg-[var(--panel)] shadow-xl">
        <div className="flex items-center gap-2 border-b border-[var(--line)] px-4 py-3">
          <Layers size={16} className="text-[var(--accent)]" />
          <div className="flex-1">
            <h2 className="text-[14px] font-semibold text-[var(--ink)]">Multi-run</h2>
            <p className="text-[11px] text-[var(--ink-faint)]">
              Les variables viennent du schéma actuel (sources eau/air, UA, etc.).
              {boundaryCount > 0
                ? ` ${boundaryCount} condition(s) limite détectée(s).`
                : " Aucune source eau/air — ajoute des BrineSource pour balayer T eau."}
            </p>
          </div>
          <button type="button" className="toolish" onClick={onClose} aria-label="Fermer">
            <X size={16} />
          </button>
        </div>

        <div className="flex-1 space-y-4 overflow-y-auto px-4 py-3">
          <div className="flex flex-wrap items-center gap-2">
            <button
              type="button"
              className="rounded-md border border-[var(--line)] bg-[var(--chrome-2)] px-2.5 py-1 text-[11px] text-[var(--ink-dim)] hover:border-[var(--accent)] hover:text-[var(--accent)]"
              onClick={resetToWaterTemps}
            >
              Préremplir T eau évap + cond
            </button>
            <span className="text-[10px] text-[var(--ink-faint)]">
              Ex. : balayer <span className="mono">evap_water_in.t_set_c</span> et{" "}
              <span className="mono">cond_water_in.t_set_c</span>
            </span>
          </div>

          <div className="space-y-2">
            <div className="flex items-center justify-between">
              <span className="eyebrow">Axes à balayer</span>
              <button
                type="button"
                className="inline-flex items-center gap-1 text-[12px] text-[var(--accent)]"
                onClick={() => addAxis()}
                disabled={targets.length === 0}
              >
                <Plus size={12} /> Ajouter un axe
              </button>
            </div>

            {targets.length === 0 && (
              <p className="rounded-md border border-dashed border-[var(--line)] p-3 text-[12px] text-[var(--warn)]">
                Schéma vide — charge un exemple ou place des composants avant le multi-run.
              </p>
            )}

            {sweeps.map((sweep, i) => {
              const selected = targets.find((t) => t.path === sweep.path);
              return (
                <div
                  key={`${sweep.path}-${i}`}
                  className="grid grid-cols-[minmax(0,2fr)_minmax(0,1.4fr)_auto] items-end gap-2 rounded-md border border-[var(--line)] bg-[var(--chrome)] p-2.5"
                >
                  <label className="flex min-w-0 flex-col gap-1">
                    <span className="eyebrow">Variable du schéma</span>
                    <select
                      className="ek-select w-full"
                      value={sweep.path}
                      onChange={(e) => pickTarget(i, e.target.value)}
                    >
                      {[...targetsByGroup.entries()].map(([group, list]) => (
                        <optgroup key={group} label={GROUP_LABEL[group]}>
                          {list.map((t) => (
                            <option key={t.path} value={t.path}>
                              {t.label}
                              {t.current !== undefined ? `  [actuel: ${t.current}]` : ""}
                            </option>
                          ))}
                        </optgroup>
                      ))}
                      {!selected && (
                        <option value={sweep.path}>{sweep.path} (hors liste)</option>
                      )}
                    </select>
                    <span className="mono truncate text-[10px] text-[var(--ink-faint)]">
                      {sweep.path}
                      {selected?.current !== undefined ? ` · actuel ${selected.current}` : ""}
                    </span>
                  </label>

                  <label className="flex min-w-0 flex-col gap-1">
                    <span className="eyebrow">
                      Valeurs {selected?.unit ? `(${selected.unit})` : ""} — séparées par des virgules
                    </span>
                    <input
                      className="ek-select mono w-full"
                      value={sweep.valuesText}
                      onChange={(e) => setAxis(i, { valuesText: e.target.value })}
                      placeholder={
                        selected?.paramKey === "t_set_c"
                          ? "10, 12, 14"
                          : "val1, val2, val3"
                      }
                    />
                  </label>

                  <button
                    type="button"
                    className="mb-0.5 rounded p-1.5 text-[var(--ink-faint)] hover:bg-[var(--chrome-2)]"
                    onClick={() => setSweeps((all) => all.filter((_, j) => j !== i))}
                    disabled={sweeps.length <= 1}
                    aria-label="Retirer l’axe"
                  >
                    <Trash2 size={14} />
                  </button>
                </div>
              );
            })}
          </div>

          <div className="flex flex-wrap items-center gap-4">
            <label className="flex items-center gap-2 text-[12px] text-[var(--ink-dim)]">
              Parallélisme
              <input
                type="number"
                min={1}
                max={16}
                className="ek-select mono w-16"
                value={concurrency}
                onChange={(e) => setConcurrency(Number(e.target.value) || 1)}
              />
            </label>
            <span className="mono text-[11px] text-[var(--ink-faint)]">
              {cases.length} cas · produit cartésien des axes
            </span>
          </div>

          {error && <p className="text-[12px] text-[var(--warn)]">{error}</p>}

          {results && (
            <div className="overflow-x-auto rounded-md border border-[var(--line)]">
              <table className="w-full text-left text-[11px]">
                <thead className="bg-[var(--chrome)] text-[var(--ink-faint)]">
                  <tr>
                    <th className="px-2 py-1.5 font-medium">Cas</th>
                    <th className="px-2 py-1.5 font-medium">Statut</th>
                    <th className="px-2 py-1.5 font-medium">COP</th>
                    <th className="px-2 py-1.5 font-medium">Qcool kW</th>
                    <th className="px-2 py-1.5 font-medium">Wcomp kW</th>
                    <th className="px-2 py-1.5 font-medium">ms</th>
                  </tr>
                </thead>
                <tbody>
                  {results.map((r) => {
                    const k = extractKpis(r.result);
                    return (
                      <tr key={r.case.id} className="border-t border-[var(--line)]">
                        <td className="max-w-[280px] px-2 py-1.5 font-medium text-[var(--ink)]">
                          {r.case.label}
                        </td>
                        <td className="px-2 py-1.5 mono">
                          {r.ok ? k.status : r.error ?? "failed"}
                        </td>
                        <td className="px-2 py-1.5 mono">
                          {k.cop != null ? k.cop.toFixed(3) : "—"}
                        </td>
                        <td className="px-2 py-1.5 mono">
                          {k.qCoolKw != null ? k.qCoolKw.toFixed(2) : "—"}
                        </td>
                        <td className="px-2 py-1.5 mono">
                          {k.powerKw != null ? k.powerKw.toFixed(2) : "—"}
                        </td>
                        <td className="px-2 py-1.5 mono">{Math.round(r.durationMs)}</td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}
        </div>

        <div className="flex items-center justify-between border-t border-[var(--line)] px-4 py-3">
          <span className="mono text-[11px] text-[var(--ink-faint)]">
            {running
              ? `Calcul ${progress.done}/${progress.total}…`
              : "Chaque cas = un POST /api/simulate (moteur CLI)"}
          </span>
          <button
            type="button"
            disabled={running || nodes.length === 0}
            onClick={() => void onRun()}
            className="flex items-center gap-1.5 rounded-md bg-[var(--accent)] px-4 py-1.5 text-[13px] font-semibold text-white disabled:opacity-50"
          >
            {running ? <Loader2 size={14} className="animate-spin" /> : <Play size={14} />}
            {running ? "En cours" : "Lancer tous les cas"}
          </button>
        </div>
      </div>

      <style jsx>{`
        .toolish {
          border-radius: 6px;
          padding: 6px;
          color: var(--ink-dim);
        }
        .toolish:hover {
          background: var(--chrome-2);
        }
        :global(.ek-select) {
          border: 1px solid var(--line);
          background: var(--chrome-2);
          border-radius: 6px;
          padding: 4px 8px;
          font-size: 12px;
          color: var(--ink);
        }
      `}</style>
    </div>
  );
}
