"use client";

import {
  Background,
  Controls,
  MiniMap,
  ReactFlow,
  ReactFlowProvider,
  useEdgesState,
  useNodesState,
  useReactFlow,
} from "@xyflow/react";
import "@xyflow/react/dist/style.css";
import { useCallback, useEffect, useMemo, useState } from "react";
import { ChevronLeft, ChevronRight, ShieldCheck } from "lucide-react";
import { ZTFlowNode } from "./ZTFlowNode";
import { ZERO_TRUST_SCENARIOS } from "./scenarios";
import type { ZTScenarioDefinition, ZTScenarioStep } from "./types";
import { PILLAR_LABELS } from "./types";
import { cn } from "@/lib/utils";

const nodeTypes = { ztNode: ZTFlowNode };

const CROSS_CUTTING = [
  "Never trust, always verify — aucune confiance implicite au réseau seul.",
  "Moindre privilège sur les accès, comptes de service et flux.",
  "Supposer la compromission : limiter le rayon d’explosion (blast radius).",
  "Vérification continue : identité, contexte et signaux de risque.",
  "Journalisation, corrélation et observabilité pour détecter les abus.",
];

function applyStepStyle(
  scenario: ZTScenarioDefinition,
  step: ZTScenarioStep | undefined,
) {
  const hn = step?.highlightNodes ?? [];
  const he = step?.highlightEdges ?? [];
  const nodeDim =
    hn.length > 0 ? (id: string) => !hn.includes(id) : () => false;
  const edgeDim =
    he.length > 0 ? (id: string) => !he.includes(id) : () => false;

  const nodes = scenario.nodes.map((n) => ({
    ...n,
    className: cn(
      "transition-all duration-300",
      nodeDim(n.id) ? "opacity-[0.38]" : "opacity-100",
      hn.includes(n.id) &&
        "ring-2 ring-araucaria-400 ring-offset-2 ring-offset-cosmos-950 rounded-xl",
    ),
  }));

  const edges = scenario.edges.map((e) => {
    const dimE = edgeDim(e.id);
    const baseStyle = (e.style as Record<string, unknown> | undefined) ?? {};
    return {
      ...e,
      animated: he.length === 0 ? e.animated : he.includes(e.id),
      style: {
        ...baseStyle,
        opacity: dimE ? 0.32 : 1,
      },
      labelStyle: {
        ...(e.labelStyle as object),
        opacity: dimE ? 0.45 : 1,
      },
      zIndex: he.includes(e.id) ? 10 : 0,
    };
  });

  return { nodes, edges };
}

function FitViewSync({
  scenarioId,
  stepIndex,
}: {
  scenarioId: string;
  stepIndex: number;
}) {
  const { fitView } = useReactFlow();

  const run = useCallback(() => {
    const id = requestAnimationFrame(() => {
      fitView({ padding: 0.18, duration: 280, maxZoom: 1.35 });
    });
    return () => cancelAnimationFrame(id);
  }, [fitView]);

  useEffect(() => {
    const t = setTimeout(run, 60);
    return () => clearTimeout(t);
  }, [scenarioId, stepIndex, run]);

  return null;
}

function FlowCanvas({
  scenario,
  step,
}: {
  scenario: ZTScenarioDefinition;
  step: ZTScenarioStep | undefined;
}) {
  const { nodes: initialNodes, edges: initialEdges } = useMemo(
    () => applyStepStyle(scenario, step),
    [scenario, step],
  );

  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);

  useEffect(() => {
    const styled = applyStepStyle(scenario, step);
    setNodes(styled.nodes);
    setEdges(styled.edges);
  }, [scenario, step, setNodes, setEdges]);

  return (
    <div className="h-[min(70vh,560px)] min-h-[420px] w-full rounded-xl border border-cosmos-700 bg-cosmos-950">
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        nodeTypes={nodeTypes}
        fitView
        attributionPosition="bottom-left"
        proOptions={{ hideAttribution: true }}
        className="bg-cosmos-950"
        defaultEdgeOptions={{
          type: "smoothstep",
        }}
        aria-label="Schéma interactif des flux et des composants de sécurité"
      >
        <FitViewSync
          scenarioId={scenario.id}
          stepIndex={step ? scenario.steps.indexOf(step) : 0}
        />
        <Background color="#475569" gap={20} size={1} />
        <Controls
          className="!m-3 !border-cosmos-600 !bg-cosmos-900 !fill-nieve [&_button]:!border-cosmos-600 [&_button:hover]:!bg-cosmos-800"
          showInteractive={false}
        />
        <MiniMap
          nodeStrokeWidth={2}
          className="!m-3 !rounded-lg !border !border-cosmos-600 !bg-cosmos-900"
          maskColor="rgba(15, 23, 42, 0.75)"
        />
      </ReactFlow>
    </div>
  );
}

export function ZeroTrustScenarioViewer() {
  const [scenarioIndex, setScenarioIndex] = useState(0);
  const [stepIndex, setStepIndex] = useState(0);

  const scenario = ZERO_TRUST_SCENARIOS[scenarioIndex]!;
  const step = scenario.steps[stepIndex];

  useEffect(() => {
    setStepIndex(0);
  }, [scenarioIndex]);

  const goPrev = () =>
    setStepIndex((i) => Math.max(0, i - 1));
  const goNext = () =>
    setStepIndex((i) => Math.min(scenario.steps.length - 1, i + 1));

  return (
    <div className="space-y-8">
      <div className="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
        <div className="max-w-xl">
          <label htmlFor="zt-scenario" className="sr-only">
            Choisir un scénario
          </label>
          <select
            id="zt-scenario"
            value={scenario.id}
            onChange={(e) => {
              const idx = ZERO_TRUST_SCENARIOS.findIndex(
                (s) => s.id === e.target.value,
              );
              if (idx >= 0) setScenarioIndex(idx);
            }}
            className="w-full rounded-lg border border-cosmos-600 bg-nieve px-4 py-2.5 text-sm font-medium text-cosmos-900 shadow-sm focus:border-araucaria-500 focus:outline-none focus:ring-2 focus:ring-araucaria-400 sm:max-w-md"
          >
            {ZERO_TRUST_SCENARIOS.map((s) => (
              <option key={s.id} value={s.id}>
                {s.title}
              </option>
            ))}
          </select>
          <p className="mt-2 text-sm text-muted">{scenario.subtitle}</p>
        </div>
        <div className="flex items-center gap-2">
          <button
            type="button"
            onClick={goPrev}
            disabled={stepIndex === 0}
            className="inline-flex items-center gap-1 rounded-lg border border-cosmos-600 bg-nieve px-3 py-2 text-sm font-medium text-cosmos-800 shadow-sm transition hover:bg-cosmos-50 disabled:cursor-not-allowed disabled:opacity-40"
          >
            <ChevronLeft className="h-4 w-4" aria-hidden />
            Étape précédente
          </button>
          <button
            type="button"
            onClick={goNext}
            disabled={stepIndex >= scenario.steps.length - 1}
            className="inline-flex items-center gap-1 rounded-lg border border-cosmos-600 bg-nieve px-3 py-2 text-sm font-medium text-cosmos-800 shadow-sm transition hover:bg-cosmos-50 disabled:cursor-not-allowed disabled:opacity-40"
          >
            Étape suivante
            <ChevronRight className="h-4 w-4" aria-hidden />
          </button>
        </div>
      </div>

      <p className="text-sm leading-relaxed text-cosmos-700">{scenario.intro}</p>

      <ReactFlowProvider>
        <FlowCanvas scenario={scenario} step={step} />
      </ReactFlowProvider>

      <div className="grid gap-8 lg:grid-cols-2">
        <div className="rounded-xl border border-border bg-nieve p-6 shadow-sm">
          <div className="flex items-center gap-2 text-cosmos-900">
            <ShieldCheck className="h-5 w-5 text-araucaria-600" aria-hidden />
            <h3 className="text-lg font-semibold">
              Étape {stepIndex + 1} — {step?.title}
            </h3>
          </div>
          <p className="mt-3 text-sm leading-relaxed text-muted">
            {step?.description}
          </p>
          {step && step.pillars.length > 0 && (
            <div className="mt-4">
              <p className="text-xs font-semibold uppercase tracking-wide text-cosmos-500">
                Piliers NIST SP 800-207 (rappel)
              </p>
              <ul className="mt-2 flex flex-wrap gap-2">
                {step.pillars.map((p) => (
                  <li
                    key={p}
                    className="rounded-full bg-araucaria-50 px-3 py-1 text-xs font-medium text-araucaria-900 ring-1 ring-araucaria-200"
                  >
                    {PILLAR_LABELS[p]}
                  </li>
                ))}
              </ul>
            </div>
          )}
          {step && (
            <ul className="mt-4 list-disc space-y-2 pl-5 text-sm text-cosmos-800">
              {step.practices.map((line, i) => (
                <li key={i}>{line}</li>
              ))}
            </ul>
          )}
        </div>

        <div className="rounded-xl border border-border bg-cosmos-900/5 p-6">
          <h3 className="text-lg font-semibold text-cosmos-900">
            Principes transverses Zero Trust
          </h3>
          <ul className="mt-4 space-y-3 text-sm leading-relaxed text-cosmos-800">
            {CROSS_CUTTING.map((line, i) => (
              <li key={i} className="flex gap-2">
                <span className="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-araucaria-500" />
                <span>{line}</span>
              </li>
            ))}
          </ul>
          <p className="mt-6 text-xs text-cosmos-500">
            Référence : modèle en piliers décrit dans NIST SP 800-207 (Zero Trust
            Architecture). Les libellés sont vulgarisés pour l’interface.
          </p>
        </div>
      </div>
    </div>
  );
}
