import { FormEvent, ReactNode, useEffect, useRef, useState } from "react";

import CycleBarChart from "./components/CycleBarChart";
import KpiBlock from "./components/KpiBlock";
import MachineCard from "./components/MachineCard";
import Panel from "./components/Panel";
import StatusBadge from "./components/StatusBadge";
import { fetchJson, patchJson, postJson, WS_URL } from "./lib/api";
import { Cycle, DailyOee, DashboardSnapshot, Downtime, MachineEvent, ProductionOrder, ReferenceData, Scrap } from "./lib/types";

type DetailState = {
  events: MachineEvent[];
  cycles: Cycle[];
  downtimes: Downtime[];
};

type ToastKey = "config" | "order" | "downtime" | "scrap";
type ModuleKey = "atelier" | "machine" | "trs" | "orders" | "downtimes" | "scrap" | "config";
type FormErrors = Record<ToastKey, Record<string, string>>;
type FormControl = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;

const today = new Date().toISOString().slice(0, 10);
const initialFormErrors: FormErrors = {
  config: {},
  order: {},
  downtime: {},
  scrap: {},
};

const moduleTabs: Array<{ key: ModuleKey; label: string; description: string }> = [
  { key: "atelier", label: "Atelier", description: "Vue machines" },
  { key: "machine", label: "Machine", description: "Cycles et evenements" },
  { key: "trs", label: "TRS", description: "Performance jour" },
  { key: "orders", label: "OF", description: "Ordres fabrication" },
  { key: "downtimes", label: "Arrets", description: "Qualification" },
  { key: "scrap", label: "Rebuts", description: "Declaration" },
  { key: "config", label: "Config", description: "Parametrage signal" },
];

export default function App() {
  const [dashboard, setDashboard] = useState<DashboardSnapshot | null>(null);
  const [orders, setOrders] = useState<ProductionOrder[]>([]);
  const [unqualifiedDowntimes, setUnqualifiedDowntimes] = useState<Downtime[]>([]);
  const [qualifiedDowntimes, setQualifiedDowntimes] = useState<Downtime[]>([]);
  const [scraps, setScraps] = useState<Scrap[]>([]);
  const [references, setReferences] = useState<ReferenceData | null>(null);
  const [dailyOee, setDailyOee] = useState<DailyOee | null>(null);
  const [selectedMachineId, setSelectedMachineId] = useState<number | null>(null);
  const [selectedOrderId, setSelectedOrderId] = useState<number | null>(null);
  const [activeModule, setActiveModule] = useState<ModuleKey>("atelier");
  const [machineFilter, setMachineFilter] = useState("all");
  const [machineSort, setMachineSort] = useState("code");
  const [isWorkshopMode, setIsWorkshopMode] = useState(false);
  const [nowMs, setNowMs] = useState(Date.now());
  const [detail, setDetail] = useState<DetailState>({ events: [], cycles: [], downtimes: [] });
  const [connectionStatus, setConnectionStatus] = useState("Connecting");
  const [errorMessage, setErrorMessage] = useState<string | null>(null);
  const [formErrors, setFormErrors] = useState<FormErrors>(initialFormErrors);
  const [actionErrors, setActionErrors] = useState<Record<ToastKey, string | null>>({
    config: null,
    order: null,
    downtime: null,
    scrap: null,
  });
  const [toasts, setToasts] = useState<Record<ToastKey, string | null>>({
    config: null,
    order: null,
    downtime: null,
    scrap: null,
  });
  const refreshTimer = useRef<number | null>(null);
  const toastTimers = useRef<Record<string, number>>({});

  async function loadDashboard() {
    const snapshot = await fetchJson<DashboardSnapshot>("/api/dashboard");
    setDashboard(snapshot);
    if (selectedMachineId === null && snapshot.machines.length > 0) {
      setSelectedMachineId(snapshot.machines[0].id);
    }
  }

  async function loadCollections() {
    const [loadedOrders, loadedUnqualifiedDowntimes, loadedQualifiedDowntimes, loadedScraps, loadedReferences, loadedDailyOee] = await Promise.all([
      fetchJson<ProductionOrder[]>("/api/production-orders"),
      fetchJson<Downtime[]>("/api/downtimes/unqualified"),
      fetchJson<Downtime[]>("/api/downtimes/qualified"),
      fetchJson<Scrap[]>("/api/scraps"),
      fetchJson<ReferenceData>("/api/reference-data"),
      fetchJson<DailyOee>(`/api/oee/daily?date=${today}`),
    ]);

    setOrders(loadedOrders);
    setSelectedOrderId((current) => (current && loadedOrders.some((order) => order.id === current) ? current : loadedOrders[0]?.id ?? null));
    setUnqualifiedDowntimes(loadedUnqualifiedDowntimes);
    setQualifiedDowntimes(loadedQualifiedDowntimes);
    setScraps(loadedScraps);
    setReferences(loadedReferences);
    setDailyOee(loadedDailyOee);
  }

  async function loadDetail(machineId: number) {
    const [events, cycles, downtimes] = await Promise.all([
      fetchJson<MachineEvent[]>(`/api/machines/${machineId}/events`),
      fetchJson<Cycle[]>(`/api/machines/${machineId}/cycles`),
      fetchJson<Downtime[]>(`/api/machines/${machineId}/downtimes`),
    ]);

    setDetail({ events, cycles, downtimes });
  }

  async function loadAll() {
    setErrorMessage(null);
    await Promise.all([loadDashboard(), loadCollections()]);
  }

  function showToast(key: ToastKey, message: string) {
    window.clearTimeout(toastTimers.current[key]);
    setToasts((current) => ({ ...current, [key]: message }));
    toastTimers.current[key] = window.setTimeout(() => {
      setToasts((current) => ({ ...current, [key]: null }));
    }, 3000);
  }

  useEffect(() => {
    loadAll().catch((error: Error) => {
      setErrorMessage(error.message);
      setConnectionStatus("Load failed");
    });
  }, []);

  useEffect(() => {
    const timer = window.setInterval(() => setNowMs(Date.now()), 30000);
    return () => window.clearInterval(timer);
  }, []);

  useEffect(() => {
    if (selectedMachineId === null) {
      return;
    }
    loadDetail(selectedMachineId).catch((error: Error) => setErrorMessage(error.message));
  }, [selectedMachineId]);

  useEffect(() => {
    let socket: WebSocket | null = null;
    let reconnectTimer: number | null = null;
    let attempt = 0;
    let isDisposed = false;

    function connect() {
      socket = new WebSocket(WS_URL);
      socket.onopen = () => {
        attempt = 0;
        setConnectionStatus("Live");
      };
      socket.onclose = () => {
        if (isDisposed) {
          return;
        }
        setConnectionStatus("Reconnecting");
        const delayMs = Math.min(30000, 1000 * 2 ** attempt);
        attempt += 1;
        reconnectTimer = window.setTimeout(connect, delayMs);
      };
      socket.onerror = () => setConnectionStatus("Reconnecting");
      socket.onmessage = (event) => {
        const message = JSON.parse(event.data) as { type: string; data?: DashboardSnapshot };
        if (message.type === "snapshot" && message.data) {
          setDashboard(message.data);
          return;
        }

        if (refreshTimer.current) {
          window.clearTimeout(refreshTimer.current);
        }
        refreshTimer.current = window.setTimeout(() => {
          loadAll().catch((error: Error) => setErrorMessage(error.message));
          if (selectedMachineId !== null) {
            loadDetail(selectedMachineId).catch((error: Error) => setErrorMessage(error.message));
          }
        }, 300);
      };
    }

    connect();

    return () => {
      isDisposed = true;
      if (refreshTimer.current) {
        window.clearTimeout(refreshTimer.current);
      }
      if (reconnectTimer) {
        window.clearTimeout(reconnectTimer);
      }
      socket?.close();
    };
  }, [selectedMachineId]);

  const selectedMachine = dashboard?.machines.find((machine) => machine.id === selectedMachineId) ?? null;
  const machines = dashboard?.machines ?? [];
  const selectedOrder = orders.find((order) => order.id === selectedOrderId) ?? null;
  const openDowntimeCount = unqualifiedDowntimes.filter((downtime) => downtime.end_time === null).length;
  const selectedMachineUnqualifiedDowntimes =
    selectedMachineId === null ? [] : unqualifiedDowntimes.filter((downtime) => downtime.machine_id === selectedMachineId);
  const downtimeOptions = [...unqualifiedDowntimes].sort((left, right) => {
    const leftSelected = selectedMachineId !== null && left.machine_id === selectedMachineId;
    const rightSelected = selectedMachineId !== null && right.machine_id === selectedMachineId;
    if (leftSelected !== rightSelected) {
      return Number(rightSelected) - Number(leftSelected);
    }
    if ((left.end_time === null) !== (right.end_time === null)) {
      return Number(right.end_time === null) - Number(left.end_time === null);
    }
    return new Date(left.start_time).getTime() - new Date(right.start_time).getTime();
  });
  const summaryMetrics = {
    production: machines.filter((machine) => machine.status === "production").length,
    openDowntimes: openDowntimeCount,
    unqualifiedDowntimes: unqualifiedDowntimes.length,
    producedQty: machines.reduce((total, machine) => total + machine.produced_qty, 0),
    scrapQty: machines.reduce((total, machine) => total + machine.scrap_qty, 0),
    oee: Math.round((dailyOee?.overall.oee ?? 0) * 100),
  };
  const machineStatuses = Array.from(new Set(machines.map((machine) => machine.status))).sort();
  const visibleMachines = [...machines]
    .filter((machine) => machineFilter === "all" || machine.status === machineFilter)
    .sort((left, right) => {
      if (machineSort === "oee") {
        return right.today_oee.oee - left.today_oee.oee;
      }
      if (machineSort === "stops") {
        return Number(Boolean(right.open_downtime)) - Number(Boolean(left.open_downtime));
      }
      return left.code.localeCompare(right.code);
    });

  function getFormControls(form: HTMLFormElement) {
    return Array.from(form.elements).filter((element): element is FormControl => {
      return element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement;
    });
  }

  function validateForm(form: HTMLFormElement, key: ToastKey) {
    const nextErrors: Record<string, string> = {};
    getFormControls(form).forEach((control) => {
      if (!control.name || control.disabled || control.type === "submit" || control.type === "button") {
        return;
      }
      if (!control.checkValidity()) {
        nextErrors[control.name] = control.validationMessage || "Invalid value.";
      }
    });
    setFormErrors((current) => ({ ...current, [key]: nextErrors }));
    return Object.keys(nextErrors).length === 0;
  }

  function handleFormBlur(key: ToastKey, form: HTMLFormElement) {
    validateForm(form, key);
  }

  function fieldError(key: ToastKey, name: string) {
    const message = formErrors[key][name];
    return message ? <span className="field-error">{message}</span> : null;
  }

  function actionError(key: ToastKey) {
    return actionErrors[key] ? <div className="inline-error">{actionErrors[key]}</div> : null;
  }

  async function submitOrder(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const form = event.currentTarget;
    if (!validateForm(form, "order")) {
      return;
    }
    const formData = new FormData(form);

    try {
      setActionErrors((current) => ({ ...current, order: null }));
      const createdOrder = await postJson<{ id: number; status: string }>("/api/production-orders", {
        order_number: formData.get("order_number"),
        machine_id: Number(formData.get("machine_id")),
        article_ref: formData.get("article_ref"),
        article_name: formData.get("article_name"),
        mold_ref: formData.get("mold_ref"),
        material_ref: formData.get("material_ref"),
        planned_qty: Number(formData.get("planned_qty")),
        cavities: Number(formData.get("cavities")),
        theoretical_cycle_time_sec: Number(formData.get("theoretical_cycle_time_sec")),
      });

      form.reset();
      setSelectedOrderId(createdOrder.id);
      setFormErrors((current) => ({ ...current, order: {} }));
      showToast("order", "Production order created.");
      await loadAll();
    } catch (error) {
      setActionErrors((current) => ({ ...current, order: error instanceof Error ? error.message : "Order creation failed." }));
    }
  }

  async function submitOrderUpdate(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!selectedOrder) {
      setActionErrors((current) => ({ ...current, order: "Select an OF before updating." }));
      return;
    }
    const form = event.currentTarget;
    if (!validateForm(form, "order")) {
      return;
    }
    const formData = new FormData(form);

    try {
      setActionErrors((current) => ({ ...current, order: null }));
      await patchJson(`/api/production-orders/${selectedOrder.id}`, {
        order_number: formData.get("order_number"),
        machine_id: Number(formData.get("machine_id")),
        article_ref: formData.get("article_ref"),
        article_name: formData.get("article_name"),
        mold_ref: formData.get("mold_ref"),
        material_ref: formData.get("material_ref"),
        planned_qty: Number(formData.get("planned_qty")),
        cavities: Number(formData.get("cavities")),
        theoretical_cycle_time_sec: Number(formData.get("theoretical_cycle_time_sec")),
      });

      setFormErrors((current) => ({ ...current, order: {} }));
      showToast("order", "Production order updated.");
      await loadAll();
    } catch (error) {
      setActionErrors((current) => ({ ...current, order: error instanceof Error ? error.message : "Order update failed." }));
    }
  }

  async function submitDowntimeQualification(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const form = event.currentTarget;
    if (!validateForm(form, "downtime")) {
      return;
    }
    const formData = new FormData(form);

    try {
      setActionErrors((current) => ({ ...current, downtime: null }));
      await postJson(`/api/downtimes/${formData.get("downtime_id")}/qualify`, {
        reason_code: formData.get("reason_code"),
        comment: formData.get("comment"),
        qualified_by: formData.get("qualified_by"),
      });

      form.reset();
      setFormErrors((current) => ({ ...current, downtime: {} }));
      showToast("downtime", "Downtime qualified.");
      await loadAll();
      if (selectedMachineId !== null) {
        await loadDetail(selectedMachineId);
      }
    } catch (error) {
      setActionErrors((current) => ({ ...current, downtime: error instanceof Error ? error.message : "Downtime qualification failed." }));
    }
  }

  async function submitScrap(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!selectedMachine) {
      setActionErrors((current) => ({ ...current, scrap: "Select a machine before declaring scrap." }));
      return;
    }
    const form = event.currentTarget;
    if (!validateForm(form, "scrap")) {
      return;
    }
    const formData = new FormData(form);

    try {
      setActionErrors((current) => ({ ...current, scrap: null }));
      await postJson("/api/scraps", {
        machine_id: selectedMachine.code,
        production_order_id: selectedMachine.active_order?.id ?? null,
        quantity: Number(formData.get("quantity")),
        reason_code: formData.get("reason_code"),
        comment: formData.get("comment"),
        operator_name: formData.get("operator_name"),
      });

      form.reset();
      setFormErrors((current) => ({ ...current, scrap: {} }));
      showToast("scrap", "Scrap declaration recorded.");
      await loadAll();
    } catch (error) {
      setActionErrors((current) => ({ ...current, scrap: error instanceof Error ? error.message : "Scrap declaration failed." }));
    }
  }

  async function changeOrderStatus(orderId: number, action: "start" | "pause" | "close") {
    try {
      setActionErrors((current) => ({ ...current, order: null }));
      await postJson(`/api/production-orders/${orderId}/${action}`);
      await loadAll();
    } catch (error) {
      setActionErrors((current) => ({ ...current, order: error instanceof Error ? error.message : "Order status change failed." }));
    }
  }

  async function submitMachineConfig(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!selectedMachine) {
      setActionErrors((current) => ({ ...current, config: "Select a machine before saving configuration." }));
      return;
    }

    const form = event.currentTarget;
    if (!validateForm(form, "config")) {
      return;
    }

    const formData = new FormData(form);
    try {
      setActionErrors((current) => ({ ...current, config: null }));
      await patchJson(`/api/machines/${selectedMachine.id}/config`, {
        name: formData.get("name"),
        brand: formData.get("brand"),
        model: formData.get("model"),
        is_active: formData.get("is_active") === "on",
        cycle_signal_edge: formData.get("cycle_signal_edge"),
        debounce_ms: Number(formData.get("debounce_ms")),
        min_cycle_time_sec: Number(formData.get("min_cycle_time_sec")),
        max_cycle_time_sec: Number(formData.get("max_cycle_time_sec")),
        stop_detection_delay_sec: Number(formData.get("stop_detection_delay_sec")),
      });

      setFormErrors((current) => ({ ...current, config: {} }));
      showToast("config", "Machine configuration saved.");
      await loadAll();
      await loadDetail(selectedMachine.id);
    } catch (error) {
      setActionErrors((current) => ({ ...current, config: error instanceof Error ? error.message : "Machine configuration failed." }));
    }
  }

  function selectMachine(machineId: number, module: ModuleKey = activeModule) {
    setSelectedMachineId(machineId);
    setActiveModule(module);
    if (module !== "atelier") {
      setIsWorkshopMode(false);
    }
  }

  function renderEventLabel(item: MachineEvent) {
    if (item.event_type !== "digital_input_changed") {
      return item.event_type;
    }
    const inputName = String(item.payload.input_name ?? "input");
    const inputValue = String(item.payload.input_value ?? "");
    return `${inputName} -> ${inputValue}`;
  }

  function toast(key: ToastKey) {
    return toasts[key] ? <div className="inline-toast">{toasts[key]}</div> : null;
  }

  function downtimeMachineLabel(downtime: Downtime) {
    if (downtime.machine_code) {
      return downtime.machine_code;
    }
    const machine = machines.find((item) => item.id === downtime.machine_id);
    return machine?.code ?? `Machine ${downtime.machine_id ?? "-"}`;
  }

  function downtimeOptionLabel(downtime: Downtime) {
    const state = downtime.end_time === null ? "Open" : "Ended";
    const parts = [`#${downtime.id}`, state, downtimeMachineLabel(downtime)];
    if (downtime.order_number) {
      parts.push(downtime.order_number);
    }
    return parts.join(" / ");
  }

  function downtimeStateLabel(downtime: Downtime) {
    if (downtime.reason_code) {
      return downtime.reason_code;
    }
    return downtime.end_time === null ? "Open - waiting qualification" : "Ended - waiting qualification";
  }

  function formatDurationSeconds(durationSec: number | null) {
    if (durationSec === null) {
      return "In progress";
    }
    if (durationSec < 60) {
      return `${durationSec} s`;
    }
    const minutes = Math.floor(durationSec / 60);
    const seconds = durationSec % 60;
    if (minutes < 60) {
      return seconds > 0 ? `${minutes} min ${seconds} s` : `${minutes} min`;
    }
    const hours = Math.floor(minutes / 60);
    const remainingMinutes = minutes % 60;
    return remainingMinutes > 0 ? `${hours} h ${remainingMinutes} min` : `${hours} h`;
  }

  function orderMachineLabel(order: ProductionOrder) {
    if (order.machine_code) {
      return order.machine_code;
    }
    return machines.find((machine) => machine.id === order.machine_id)?.code ?? `Machine ${order.machine_id}`;
  }

  function renderModule(): ReactNode {
    if (activeModule === "atelier") {
      return (
        <Panel
          title="Dashboard Atelier"
          subtitle="Machine status"
          actions={
            <div className="panel-actions">
              <select value={machineFilter} onChange={(event) => setMachineFilter(event.target.value)} aria-label="Filter machines by status">
                <option value="all">All statuses</option>
                {machineStatuses.map((status) => (
                  <option key={status} value={status}>
                    {status}
                  </option>
                ))}
              </select>
              <select value={machineSort} onChange={(event) => setMachineSort(event.target.value)} aria-label="Sort machines">
                <option value="code">Sort by code</option>
                <option value="oee">Sort by OEE</option>
                <option value="stops">Stops first</option>
              </select>
              <button type="button" onClick={() => setIsWorkshopMode((current) => !current)}>
                {isWorkshopMode ? "Exit fullscreen" : "Fullscreen atelier"}
              </button>
            </div>
          }
        >
          <div className="machine-grid">
            {visibleMachines.map((machine) => (
              <MachineCard
                key={machine.id}
                machine={machine}
                selected={machine.id === selectedMachineId}
                nowMs={nowMs}
                onSelect={() => selectMachine(machine.id, "machine")}
                onCreateOrder={() => selectMachine(machine.id, "orders")}
                onDeclareScrap={() => selectMachine(machine.id, "scrap")}
                onQualifyDowntime={() => selectMachine(machine.id, "downtimes")}
              />
            ))}
          </div>
          {visibleMachines.length === 0 ? <div className="empty-state">No machines match the current filter.</div> : null}
        </Panel>
      );
    }

    if (activeModule === "machine") {
      return (
        <Panel title="Detail Machine" subtitle={selectedMachine ? selectedMachine.code : "Select a machine"}>
          {selectedMachine ? (
            <div className="detail-stack">
              <div className="metric-row">
                <KpiBlock label="Status" value={<StatusBadge status={selectedMachine.status} />} />
                <KpiBlock label="Current order" value={selectedMachine.active_order?.order_number ?? "None"} />
                <KpiBlock label="Avg. cycle" value={`${selectedMachine.cycle_real_avg_sec.toFixed(1)} s`} />
                <KpiBlock label="Daily OEE" value={`${Math.round(selectedMachine.today_oee.oee * 100)}%`} />
              </div>

              <div className="machine-context">
                <div>
                  <span className="meta-label">Machine</span>
                  <strong>
                    {selectedMachine.brand} {selectedMachine.model}
                  </strong>
                </div>
                <div>
                  <span className="meta-label">Signal setup</span>
                  <strong>
                    {selectedMachine.config.cycle_signal_edge} edge / {selectedMachine.config.debounce_ms} ms /{" "}
                    {selectedMachine.config.stop_detection_delay_sec} s
                  </strong>
                </div>
                <div>
                  <span className="meta-label">Good parts</span>
                  <strong>{selectedMachine.produced_qty - selectedMachine.scrap_qty}</strong>
                </div>
              </div>

              <section className="cycle-panel">
                <div className="cycle-panel__header">
                  <h3>Recent cycles</h3>
                  <span>{detail.cycles.length} samples</span>
                </div>
                <CycleBarChart cycles={detail.cycles} theoreticalCycleTimeSec={selectedMachine.active_order?.theoretical_cycle_time_sec ?? 0} />
              </section>

              <div className="detail-columns">
                <div>
                  <h3>Recent events</h3>
                  <ul className="list">
                    {detail.events.slice(0, 8).map((item) => (
                      <li key={item.id}>
                        <strong>{renderEventLabel(item)}</strong>
                        <span>{new Date(item.timestamp).toLocaleString()}</span>
                      </li>
                    ))}
                  </ul>
                </div>
                <div>
                  <h3>Downtime history</h3>
                  <ul className="list">
                    {detail.downtimes.slice(0, 8).map((item) => (
                      <li key={item.id}>
                        <strong>{downtimeStateLabel(item)}</strong>
                        <span>
                          {new Date(item.start_time).toLocaleString()}
                          {item.end_time ? ` -> ${new Date(item.end_time).toLocaleString()}` : ""}
                        </span>
                      </li>
                    ))}
                  </ul>
                </div>
              </div>
            </div>
          ) : (
            <p>No machine selected.</p>
          )}
        </Panel>
      );
    }

    if (activeModule === "trs") {
      return (
        <Panel title="Vue TRS Journalier" subtitle={today}>
          {dailyOee ? (
            <div className="module-grid module-grid--split">
              <div className="oee-grid">
                <KpiBlock label="OEE" value={`${Math.round(dailyOee.overall.oee * 100)}%`} tone="dark" />
                <KpiBlock label="Availability" value={`${Math.round(dailyOee.overall.availability * 100)}%`} />
                <KpiBlock label="Performance" value={`${Math.round(dailyOee.overall.performance * 100)}%`} />
                <KpiBlock label="Quality" value={`${Math.round(dailyOee.overall.quality * 100)}%`} />
              </div>
              <div className="oee-mini-list">
                {machines.map((machine) => (
                  <button key={machine.id} type="button" className="oee-mini-list__item" onClick={() => selectMachine(machine.id, "machine")}>
                    <span>{machine.code}</span>
                    <strong>{Math.round(machine.today_oee.oee * 100)}%</strong>
                  </button>
                ))}
              </div>
            </div>
          ) : null}
        </Panel>
      );
    }

    if (activeModule === "orders") {
      return (
        <Panel title="Ordres de Fabrication" subtitle={selectedOrder ? `Selected ${selectedOrder.order_number}` : "Create and manage production orders"}>
          <div className="module-grid module-grid--form-table">
            <form
              className="form-grid module-form"
              onSubmit={submitOrder}
              onBlurCapture={(event) => handleFormBlur("order", event.currentTarget)}
              onInputCapture={(event) => validateForm(event.currentTarget, "order")}
              onChangeCapture={(event) => validateForm(event.currentTarget, "order")}
              noValidate
            >
              <input name="order_number" placeholder="OF number" required />
              {fieldError("order", "order_number")}
              <select name="machine_id" required defaultValue={selectedMachine?.id ?? ""}>
                <option value="" disabled>
                  Machine
                </option>
                {machines.map((machine) => (
                  <option key={machine.id} value={machine.id}>
                    {machine.code}
                  </option>
                ))}
              </select>
              {fieldError("order", "machine_id")}
              <input name="article_ref" placeholder="Article ref" required />
              {fieldError("order", "article_ref")}
              <input name="article_name" placeholder="Article name" required />
              {fieldError("order", "article_name")}
              <input name="mold_ref" placeholder="Mold ref" />
              <input name="material_ref" placeholder="Material ref" />
              <input name="planned_qty" type="number" min="1" placeholder="Planned qty" required />
              {fieldError("order", "planned_qty")}
              <input name="cavities" type="number" min="1" defaultValue="1" placeholder="Cavities" required />
              {fieldError("order", "cavities")}
              <input name="theoretical_cycle_time_sec" type="number" min="1" step="0.1" placeholder="Theoretical cycle" required />
              {fieldError("order", "theoretical_cycle_time_sec")}
              <button type="submit" className="primary-button" disabled={Object.keys(formErrors.order).length > 0}>
                Create
              </button>
              {actionError("order")}
              {toast("order")}
            </form>

            <div className="table-wrap">
              <table>
                <thead>
                  <tr>
                    <th>OF</th>
                    <th>Machine</th>
                    <th>Article</th>
                    <th>Planned</th>
                    <th>Status</th>
                    <th>Actions</th>
                  </tr>
                </thead>
                <tbody>
                  {orders.map((order) => (
                    <tr key={order.id} className={order.id === selectedOrderId ? "is-selected-row" : ""}>
                      <td>
                        <button type="button" className="link-button" onClick={() => setSelectedOrderId(order.id)}>
                          {order.order_number}
                        </button>
                      </td>
                      <td>{orderMachineLabel(order)}</td>
                      <td>{order.article_name}</td>
                      <td>{order.planned_qty}</td>
                      <td>{order.status}</td>
                      <td className="table-actions">
                        <button type="button" onClick={() => changeOrderStatus(order.id, "start")}>
                          Start
                        </button>
                        <button type="button" onClick={() => changeOrderStatus(order.id, "pause")}>
                          Pause
                        </button>
                        <button type="button" onClick={() => changeOrderStatus(order.id, "close")}>
                          Close
                        </button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>

            {selectedOrder ? (
              <section className="order-detail">
                <div className="order-detail__header">
                  <div>
                    <span className="meta-label">OF detail</span>
                    <h3>{selectedOrder.order_number}</h3>
                  </div>
                  <StatusBadge status={selectedOrder.status} />
                </div>
                <div className="order-detail__meta">
                  <div>
                    <span className="meta-label">Machine</span>
                    <strong>{orderMachineLabel(selectedOrder)}</strong>
                  </div>
                  <div>
                    <span className="meta-label">Article</span>
                    <strong>{selectedOrder.article_ref} / {selectedOrder.article_name}</strong>
                  </div>
                  <div>
                    <span className="meta-label">Cycle / cavities</span>
                    <strong>{selectedOrder.theoretical_cycle_time_sec} s / {selectedOrder.cavities}</strong>
                  </div>
                  <div>
                    <span className="meta-label">Dates</span>
                    <strong>
                      {selectedOrder.started_at ? new Date(selectedOrder.started_at).toLocaleString() : "Not started"}
                      {selectedOrder.ended_at ? ` -> ${new Date(selectedOrder.ended_at).toLocaleString()}` : ""}
                    </strong>
                  </div>
                </div>
                <form
                  className="form-grid config-form"
                  key={selectedOrder.id}
                  onSubmit={submitOrderUpdate}
                  onBlurCapture={(event) => handleFormBlur("order", event.currentTarget)}
                  onInputCapture={(event) => validateForm(event.currentTarget, "order")}
                  onChangeCapture={(event) => validateForm(event.currentTarget, "order")}
                  noValidate
                >
                  <input name="order_number" defaultValue={selectedOrder.order_number} placeholder="OF number" required />
                  <select name="machine_id" required defaultValue={selectedOrder.machine_id}>
                    {machines.map((machine) => (
                      <option key={machine.id} value={machine.id}>
                        {machine.code}
                      </option>
                    ))}
                  </select>
                  <input name="article_ref" defaultValue={selectedOrder.article_ref} placeholder="Article ref" required />
                  <input name="article_name" defaultValue={selectedOrder.article_name} placeholder="Article name" required />
                  <input name="mold_ref" defaultValue={selectedOrder.mold_ref ?? ""} placeholder="Mold ref" />
                  <input name="material_ref" defaultValue={selectedOrder.material_ref ?? ""} placeholder="Material ref" />
                  <input name="planned_qty" type="number" min="1" defaultValue={selectedOrder.planned_qty} placeholder="Planned qty" required />
                  <input name="cavities" type="number" min="1" defaultValue={selectedOrder.cavities} placeholder="Cavities" required />
                  <input
                    name="theoretical_cycle_time_sec"
                    type="number"
                    min="1"
                    step="0.1"
                    defaultValue={selectedOrder.theoretical_cycle_time_sec}
                    placeholder="Theoretical cycle"
                    required
                  />
                  <button type="submit" className="primary-button" disabled={Object.keys(formErrors.order).length > 0}>
                    Update OF
                  </button>
                  {actionError("order")}
                  {toast("order")}
                </form>
              </section>
            ) : (
              <div className="empty-state">Select an OF to see and update details.</div>
            )}
          </div>
        </Panel>
      );
    }

    if (activeModule === "downtimes") {
      return (
        <Panel
          title="Qualification Arret"
          subtitle={
            selectedMachine
              ? `${selectedMachineUnqualifiedDowntimes.length} unqualified for ${selectedMachine.code} / ${unqualifiedDowntimes.length} total`
              : `${unqualifiedDowntimes.length} unqualified downtime(s)`
          }
        >
          <div className="module-grid module-grid--form-table">
            <form
              className="form-grid module-form"
              key={selectedMachine?.id ?? "all-downtimes"}
              onSubmit={submitDowntimeQualification}
              onBlurCapture={(event) => handleFormBlur("downtime", event.currentTarget)}
              onInputCapture={(event) => validateForm(event.currentTarget, "downtime")}
              onChangeCapture={(event) => validateForm(event.currentTarget, "downtime")}
              noValidate
            >
              <select name="downtime_id" required defaultValue={selectedMachineUnqualifiedDowntimes[0]?.id ?? ""}>
                <option value="" disabled>
                  Downtime to qualify
                </option>
                {downtimeOptions.map((downtime) => (
                  <option key={downtime.id} value={downtime.id}>
                    {downtimeOptionLabel(downtime)}
                  </option>
                ))}
              </select>
              {fieldError("downtime", "downtime_id")}
              <select name="reason_code" required defaultValue="">
                <option value="" disabled>
                  Reason
                </option>
                {references?.downtime_reasons.map((reason) => (
                  <option key={reason.code} value={reason.code}>
                    {reason.label}
                  </option>
                ))}
              </select>
              {fieldError("downtime", "reason_code")}
              <input name="qualified_by" placeholder="Operator" required />
              {fieldError("downtime", "qualified_by")}
              <textarea name="comment" placeholder="Comment" rows={3} />
              <button type="submit" className="primary-button" disabled={Object.keys(formErrors.downtime).length > 0}>
                Qualify
              </button>
              {actionError("downtime")}
              {toast("downtime")}
            </form>

            <div className="downtime-board">
              {selectedMachine ? (
                <section className="downtime-focus">
                  <span className="meta-label">Selected machine</span>
                  <strong>{selectedMachine.code}</strong>
                  {selectedMachineUnqualifiedDowntimes.length > 0 ? (
                    <ul className="timeline-list timeline-list--compact">
                      {selectedMachineUnqualifiedDowntimes.map((item) => (
                        <li key={item.id}>
                          <div>
                            <strong>{downtimeOptionLabel(item)}</strong>
                            <span>{downtimeStateLabel(item)}</span>
                          </div>
                          <time>{new Date(item.start_time).toLocaleString()}</time>
                        </li>
                      ))}
                    </ul>
                  ) : (
                    <div className="empty-state">No unqualified downtime for {selectedMachine.code}.</div>
                  )}
                </section>
              ) : null}

              <section>
                <span className="meta-label">All stops waiting qualification</span>
                <ul className="timeline-list">
                  {downtimeOptions.map((item) => (
                    <li key={item.id} className={item.machine_id === selectedMachineId ? "is-current-machine" : ""}>
                      <div>
                        <strong>{downtimeMachineLabel(item)}</strong>
                        <span>
                          {item.order_number ? `${item.order_number} / ` : ""}
                          {downtimeStateLabel(item)}
                        </span>
                      </div>
                      <time>{new Date(item.start_time).toLocaleString()}</time>
                    </li>
                  ))}
                </ul>
              </section>

              <section>
                <span className="meta-label">Qualified stops history</span>
                <ul className="timeline-list timeline-list--qualified">
                  {qualifiedDowntimes.map((item) => (
                    <li key={item.id} className={item.machine_id === selectedMachineId ? "is-current-machine" : ""}>
                      <div>
                        <strong>
                          {downtimeMachineLabel(item)} / {item.reason_code}
                        </strong>
                        <span>
                          {item.order_number ? `${item.order_number} / ` : ""}
                          {item.qualified_by ? `By ${item.qualified_by} / ` : ""}
                          {formatDurationSeconds(item.duration_sec)}
                          {item.comment ? ` / ${item.comment}` : ""}
                        </span>
                      </div>
                      <time>
                        {new Date(item.start_time).toLocaleString()}
                        {item.end_time ? ` -> ${new Date(item.end_time).toLocaleString()}` : ""}
                      </time>
                    </li>
                  ))}
                </ul>
                {qualifiedDowntimes.length === 0 ? <div className="empty-state">No qualified downtime history yet.</div> : null}
              </section>
            </div>
            {unqualifiedDowntimes.length === 0 ? <div className="empty-state">No downtime currently needs qualification.</div> : null}
          </div>
        </Panel>
      );
    }

    if (activeModule === "scrap") {
      return (
        <Panel title="Saisie Rebut" subtitle={selectedMachine?.code ?? "Select machine"}>
          <div className="module-grid module-grid--form-table">
            <form
              className="form-grid module-form"
              onSubmit={submitScrap}
              onBlurCapture={(event) => handleFormBlur("scrap", event.currentTarget)}
              onInputCapture={(event) => validateForm(event.currentTarget, "scrap")}
              onChangeCapture={(event) => validateForm(event.currentTarget, "scrap")}
              noValidate
            >
              <input name="operator_name" placeholder="Operator" required />
              {fieldError("scrap", "operator_name")}
              <input name="quantity" type="number" min="1" placeholder="Quantity" required />
              {fieldError("scrap", "quantity")}
              <select name="reason_code" required defaultValue="">
                <option value="" disabled>
                  Scrap reason
                </option>
                {references?.scrap_reasons.map((reason) => (
                  <option key={reason.code} value={reason.code}>
                    {reason.label}
                  </option>
                ))}
              </select>
              {fieldError("scrap", "reason_code")}
              <textarea name="comment" placeholder="Comment" rows={3} />
              <button type="submit" className="primary-button" disabled={!selectedMachine || Object.keys(formErrors.scrap).length > 0}>
                Record
              </button>
              {actionError("scrap")}
              {toast("scrap")}
            </form>

            <ul className="list">
              {scraps.slice(0, 12).map((scrap) => (
                <li key={scrap.id}>
                  <strong>
                    {scrap.quantity} pcs / {scrap.reason_code}
                  </strong>
                  <span>{new Date(scrap.timestamp).toLocaleString()}</span>
                </li>
              ))}
            </ul>
            {scraps.length === 0 ? <div className="empty-state">No scrap has been declared yet.</div> : null}
          </div>
        </Panel>
      );
    }

    return (
      <Panel title="Config Machine" subtitle={selectedMachine?.code ?? "No machine selected"}>
        {selectedMachine ? (
          <form
            className="form-grid config-form"
            onSubmit={submitMachineConfig}
            onBlurCapture={(event) => handleFormBlur("config", event.currentTarget)}
            onInputCapture={(event) => validateForm(event.currentTarget, "config")}
            onChangeCapture={(event) => validateForm(event.currentTarget, "config")}
            key={selectedMachine.id}
            noValidate
          >
            <input name="name" placeholder="Display name" defaultValue={selectedMachine.config.name} required />
            {fieldError("config", "name")}
            <input name="brand" placeholder="Brand" defaultValue={selectedMachine.config.brand ?? ""} />
            <input name="model" placeholder="Model" defaultValue={selectedMachine.config.model ?? ""} />
            <label className="checkbox-field">
              <input name="is_active" type="checkbox" defaultChecked={selectedMachine.config.is_active} />
              <span>Active on dashboard</span>
            </label>
            <select name="cycle_signal_edge" defaultValue={selectedMachine.config.cycle_signal_edge}>
              <option value="rising">Rising edge</option>
              <option value="falling">Falling edge</option>
            </select>
            <input name="debounce_ms" type="number" min="0" defaultValue={selectedMachine.config.debounce_ms} placeholder="Debounce ms" required />
            {fieldError("config", "debounce_ms")}
            <input
              name="min_cycle_time_sec"
              type="number"
              min="1"
              defaultValue={selectedMachine.config.min_cycle_time_sec}
              placeholder="Min cycle sec"
              required
            />
            {fieldError("config", "min_cycle_time_sec")}
            <input
              name="max_cycle_time_sec"
              type="number"
              min="1"
              defaultValue={selectedMachine.config.max_cycle_time_sec}
              placeholder="Max cycle sec"
              required
            />
            {fieldError("config", "max_cycle_time_sec")}
            <input
              name="stop_detection_delay_sec"
              type="number"
              min="1"
              defaultValue={selectedMachine.config.stop_detection_delay_sec}
              placeholder="Stop delay sec"
              required
            />
            {fieldError("config", "stop_detection_delay_sec")}
            <button type="submit" className="primary-button" disabled={Object.keys(formErrors.config).length > 0}>
              Save
            </button>
            {actionError("config")}
            {toast("config")}
          </form>
        ) : (
          <p>No machine selected.</p>
        )}
      </Panel>
    );
  }

  return (
    <div className={`app-shell ${isWorkshopMode && activeModule === "atelier" ? "app-shell--workshop" : ""}`}>
      <main className="workspace">
        <header className="hero">
          <div>
            <p className="eyebrow">Plast Track MVP</p>
            <h1>Workshop supervision</h1>
          </div>
          <div className="hero__status">
            <span className="hero__dot" aria-hidden="true" />
            <strong>{connectionStatus}</strong>
            {errorMessage ? <p>{errorMessage}</p> : null}
          </div>
        </header>

        {connectionStatus === "Reconnecting" ? <div className="connection-banner">Reconnecting...</div> : null}

        <section className="summary-ribbon" aria-label="Workshop summary">
          <KpiBlock label="Global OEE" value={`${summaryMetrics.oee}%`} subLabel="Daily aggregate" tone="dark" />
          <KpiBlock label="Production" value={summaryMetrics.production} subLabel={`${machines.length} machines monitored`} />
          <KpiBlock label="Open stops" value={summaryMetrics.openDowntimes} subLabel={`${summaryMetrics.unqualifiedDowntimes} unqualified`} />
          <KpiBlock label="Output / scrap" value={`${summaryMetrics.producedQty} / ${summaryMetrics.scrapQty}`} subLabel="Pieces today" />
        </section>

        <nav className="module-tabs" aria-label="Modules">
          {moduleTabs.map((tab) => (
            <button
              key={tab.key}
              type="button"
              className={`module-tabs__button ${activeModule === tab.key ? "is-active" : ""}`}
              onClick={() => {
                setActiveModule(tab.key);
                if (tab.key !== "atelier") {
                  setIsWorkshopMode(false);
                }
              }}
            >
              <span>{tab.label}</span>
              <small>{tab.description}</small>
            </button>
          ))}
        </nav>

        <section className="module-view">{renderModule()}</section>
      </main>
    </div>
  );
}
