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;
type Language = "en" | "fr";

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

function FieldLabel({ label, error, children }: { label: string; error?: ReactNode; children: ReactNode }) {
  return (
    <label className="form-field">
      <span className="input-label">{label}</span>
      {children}
      {error}
    </label>
  );
}

export default function App() {
  const [showSplash, setShowSplash] = useState(true);
  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 [language, setLanguage] = useState<Language>(() => (localStorage.getItem("plast-track-language") as Language | null) ?? "en");
  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>>({});

  function t(en: string, fr: string) {
    return language === "fr" ? fr : en;
  }

  useEffect(() => {
    const timer = window.setTimeout(() => setShowSplash(false), 900);
    return () => window.clearTimeout(timer);
  }, []);

  const moduleTabs: Array<{ key: ModuleKey; label: string; description: string }> = [
    { key: "atelier", label: t("Workshop", "Atelier"), description: t("Machines view", "Vue machines") },
    { key: "machine", label: "Machine", description: t("Cycles and events", "Cycles et evenements") },
    { key: "trs", label: "OEE/TRS", description: t("Daily performance", "Performance jour") },
    { key: "orders", label: t("Orders", "OF"), description: t("Production orders", "Ordres fabrication") },
    { key: "downtimes", label: t("Stops", "Arrets"), description: "Qualification" },
    { key: "scrap", label: t("Scrap", "Rebuts"), description: t("Declaration", "Declaration") },
    { key: "config", label: "Config", description: t("Signal setup", "Parametrage signal") },
  ];

  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(() => {
    localStorage.setItem("plast-track-language", language);
  }, [language]);

  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", t("Production order created.", "Ordre de fabrication cree."));
      await loadAll();
    } catch (error) {
      setActionErrors((current) => ({ ...current, order: error instanceof Error ? error.message : t("Order creation failed.", "Creation OF echouee.") }));
    }
  }

  async function submitOrderUpdate(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!selectedOrder) {
      setActionErrors((current) => ({ ...current, order: t("Select an OF before updating.", "Selectionner un OF avant modification.") }));
      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", t("Production order updated.", "Ordre de fabrication modifie."));
      await loadAll();
    } catch (error) {
      setActionErrors((current) => ({ ...current, order: error instanceof Error ? error.message : t("Order update failed.", "Modification OF echouee.") }));
    }
  }

  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", t("Downtime qualified.", "Arret qualifie."));
      await loadAll();
      if (selectedMachineId !== null) {
        await loadDetail(selectedMachineId);
      }
    } catch (error) {
      setActionErrors((current) => ({ ...current, downtime: error instanceof Error ? error.message : t("Downtime qualification failed.", "Qualification arret echouee.") }));
    }
  }

  async function submitScrap(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!selectedMachine) {
      setActionErrors((current) => ({ ...current, scrap: t("Select a machine before declaring scrap.", "Selectionner une machine avant de declarer le rebut.") }));
      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", t("Scrap declaration recorded.", "Declaration rebut enregistree."));
      await loadAll();
    } catch (error) {
      setActionErrors((current) => ({ ...current, scrap: error instanceof Error ? error.message : t("Scrap declaration failed.", "Declaration rebut echouee.") }));
    }
  }

  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 : t("Order status change failed.", "Changement statut OF echoue.") }));
    }
  }

  async function submitMachineConfig(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!selectedMachine) {
      setActionErrors((current) => ({ ...current, config: t("Select a machine before saving configuration.", "Selectionner une machine avant d'enregistrer la 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", t("Machine configuration saved.", "Configuration machine enregistree."));
      await loadAll();
      await loadDetail(selectedMachine.id);
    } catch (error) {
      setActionErrors((current) => ({ ...current, config: error instanceof Error ? error.message : t("Machine configuration failed.", "Configuration machine echouee.") }));
    }
  }

  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 ? t("Open", "Ouvert") : t("Ended", "Termine");
    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 ? t("Open - waiting qualification", "Ouvert - en attente de qualification") : t("Ended - waiting qualification", "Termine - en attente de qualification");
  }

  function formatDurationSeconds(durationSec: number | null) {
    if (durationSec === null) {
      return t("In progress", "En cours");
    }
    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 connectionLabel(status: string) {
    if (status === "Connecting") {
      return t("Connecting", "Connexion");
    }
    if (status === "Load failed") {
      return t("Load failed", "Chargement echoue");
    }
    if (status === "Live") {
      return t("Live", "Direct");
    }
    if (status === "Reconnecting") {
      return t("Reconnecting", "Reconnexion");
    }
    return status;
  }

  function renderModule(): ReactNode {
    if (activeModule === "atelier") {
      return (
        <Panel
          title={t("Workshop dashboard", "Tableau atelier")}
          subtitle={t("Machine status", "Etat machines")}
          actions={
            <div className="panel-actions">
              <select value={machineFilter} onChange={(event) => setMachineFilter(event.target.value)} aria-label={t("Filter machines by status", "Filtrer les machines par etat")}>
                <option value="all">{t("All statuses", "Tous les etats")}</option>
                {machineStatuses.map((status) => (
                  <option key={status} value={status}>
                    {status}
                  </option>
                ))}
              </select>
              <select value={machineSort} onChange={(event) => setMachineSort(event.target.value)} aria-label={t("Sort machines", "Trier les machines")}>
                <option value="code">{t("Sort by code", "Trier par code")}</option>
                <option value="oee">{t("Sort by OEE", "Trier par TRS")}</option>
                <option value="stops">{t("Stops first", "Arrets en premier")}</option>
              </select>
              <button type="button" onClick={() => setIsWorkshopMode((current) => !current)}>
                {isWorkshopMode ? t("Exit fullscreen", "Quitter plein ecran") : t("Fullscreen workshop", "Atelier plein ecran")}
              </button>
            </div>
          }
        >
          <div className="machine-grid">
            {visibleMachines.map((machine) => (
              <MachineCard
                key={machine.id}
                machine={machine}
                selected={machine.id === selectedMachineId}
                nowMs={nowMs}
                language={language}
                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">{t("No machines match the current filter.", "Aucune machine ne correspond au filtre.")}</div> : null}
        </Panel>
      );
    }

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

              <div className="machine-context">
                <div>
                  <span className="meta-label">{t("Machine", "Machine")}</span>
                  <strong>
                    {selectedMachine.brand} {selectedMachine.model}
                  </strong>
                </div>
                <div>
                  <span className="meta-label">{t("Signal setup", "Parametrage signal")}</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">{t("Good parts", "Pieces bonnes")}</span>
                  <strong>{selectedMachine.produced_qty - selectedMachine.scrap_qty}</strong>
                </div>
              </div>

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

              <div className="detail-columns">
                <div>
                  <h3>{t("Recent events", "Evenements recents")}</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>{t("Downtime history", "Historique arrets")}</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>{t("No machine selected.", "Aucune machine selectionnee.")}</p>
          )}
        </Panel>
      );
    }

    if (activeModule === "trs") {
      return (
        <Panel title={t("Daily OEE view", "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={t("Availability", "Disponibilite")} value={`${Math.round(dailyOee.overall.availability * 100)}%`} />
                <KpiBlock label={t("Performance", "Performance")} value={`${Math.round(dailyOee.overall.performance * 100)}%`} />
                <KpiBlock label={t("Quality", "Qualite")} 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={t("Production orders", "Ordres de fabrication")}
          subtitle={selectedOrder ? `${t("Selected", "Selectionne")} ${selectedOrder.order_number}` : t("Create and manage production orders", "Creer et gerer les ordres de fabrication")}
        >
          <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
            >
              <FieldLabel label={t("OF number", "Numero OF")} error={fieldError("order", "order_number")}>
                <input name="order_number" placeholder="OF-2001" required />
              </FieldLabel>
              <FieldLabel label={t("Machine", "Machine")} error={fieldError("order", "machine_id")}>
                <select name="machine_id" required defaultValue={selectedMachine?.id ?? ""}>
                  <option value="" disabled>
                    {t("Select machine", "Selectionner machine")}
                  </option>
                  {machines.map((machine) => (
                    <option key={machine.id} value={machine.id}>
                      {machine.code}
                    </option>
                  ))}
                </select>
              </FieldLabel>
              <FieldLabel label={t("Article reference", "Reference article")} error={fieldError("order", "article_ref")}>
                <input name="article_ref" placeholder="ART-001" required />
              </FieldLabel>
              <FieldLabel label={t("Article name", "Nom article")} error={fieldError("order", "article_name")}>
                <input name="article_name" placeholder={t("Part name", "Nom piece")} required />
              </FieldLabel>
              <FieldLabel label={t("Mold reference", "Reference moule")}>
                <input name="mold_ref" placeholder="M-001" />
              </FieldLabel>
              <FieldLabel label={t("Material reference", "Reference matiere")}>
                <input name="material_ref" placeholder="PP" />
              </FieldLabel>
              <FieldLabel label={t("Planned quantity", "Quantite prevue")} error={fieldError("order", "planned_qty")}>
                <input name="planned_qty" type="number" min="1" placeholder="1000" required />
              </FieldLabel>
              <FieldLabel label={t("Cavities", "Empreintes")} error={fieldError("order", "cavities")}>
                <input name="cavities" type="number" min="1" defaultValue="1" required />
              </FieldLabel>
              <FieldLabel label={t("Theoretical cycle time", "Temps de cycle theorique")} error={fieldError("order", "theoretical_cycle_time_sec")}>
                <input name="theoretical_cycle_time_sec" type="number" min="1" step="0.1" placeholder="20" required />
              </FieldLabel>
              <button type="submit" className="primary-button" disabled={Object.keys(formErrors.order).length > 0}>
                {t("Create", "Creer")}
              </button>
              {actionError("order")}
              {toast("order")}
            </form>

            <div className="table-wrap">
              <table>
                <thead>
                  <tr>
                    <th>{t("OF", "OF")}</th>
                    <th>{t("Machine", "Machine")}</th>
                    <th>{t("Article", "Article")}</th>
                    <th>{t("Planned", "Prevu")}</th>
                    <th>{t("Status", "Etat")}</th>
                    <th>{t("Actions", "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")}>
                          {t("Start", "Demarrer")}
                        </button>
                        <button type="button" onClick={() => changeOrderStatus(order.id, "pause")}>
                          {t("Pause", "Pause")}
                        </button>
                        <button type="button" onClick={() => changeOrderStatus(order.id, "close")}>
                          {t("Close", "Cloturer")}
                        </button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>

            {selectedOrder ? (
              <section className="order-detail">
                <div className="order-detail__header">
                  <div>
                    <span className="meta-label">{t("OF detail", "Detail OF")}</span>
                    <h3>{selectedOrder.order_number}</h3>
                  </div>
                  <StatusBadge status={selectedOrder.status} language={language} />
                </div>
                <div className="order-detail__meta">
                  <div>
                    <span className="meta-label">{t("Machine", "Machine")}</span>
                    <strong>{orderMachineLabel(selectedOrder)}</strong>
                  </div>
                  <div>
                    <span className="meta-label">{t("Article", "Article")}</span>
                    <strong>{selectedOrder.article_ref} / {selectedOrder.article_name}</strong>
                  </div>
                  <div>
                    <span className="meta-label">{t("Cycle / cavities", "Cycle / empreintes")}</span>
                    <strong>{selectedOrder.theoretical_cycle_time_sec} s / {selectedOrder.cavities}</strong>
                  </div>
                  <div>
                    <span className="meta-label">{t("Dates", "Dates")}</span>
                    <strong>
                      {selectedOrder.started_at ? new Date(selectedOrder.started_at).toLocaleString() : t("Not started", "Non demarre")}
                      {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
                >
                  <FieldLabel label={t("OF number", "Numero OF")}>
                    <input name="order_number" defaultValue={selectedOrder.order_number} required />
                  </FieldLabel>
                  <FieldLabel label={t("Machine", "Machine")}>
                    <select name="machine_id" required defaultValue={selectedOrder.machine_id}>
                      {machines.map((machine) => (
                        <option key={machine.id} value={machine.id}>
                          {machine.code}
                        </option>
                      ))}
                    </select>
                  </FieldLabel>
                  <FieldLabel label={t("Article reference", "Reference article")}>
                    <input name="article_ref" defaultValue={selectedOrder.article_ref} required />
                  </FieldLabel>
                  <FieldLabel label={t("Article name", "Nom article")}>
                    <input name="article_name" defaultValue={selectedOrder.article_name} required />
                  </FieldLabel>
                  <FieldLabel label={t("Mold reference", "Reference moule")}>
                    <input name="mold_ref" defaultValue={selectedOrder.mold_ref ?? ""} />
                  </FieldLabel>
                  <FieldLabel label={t("Material reference", "Reference matiere")}>
                    <input name="material_ref" defaultValue={selectedOrder.material_ref ?? ""} />
                  </FieldLabel>
                  <FieldLabel label={t("Planned quantity", "Quantite prevue")}>
                    <input name="planned_qty" type="number" min="1" defaultValue={selectedOrder.planned_qty} required />
                  </FieldLabel>
                  <FieldLabel label={t("Cavities", "Empreintes")}>
                    <input name="cavities" type="number" min="1" defaultValue={selectedOrder.cavities} required />
                  </FieldLabel>
                  <FieldLabel label={t("Theoretical cycle time", "Temps de cycle theorique")}>
                    <input name="theoretical_cycle_time_sec" type="number" min="1" step="0.1" defaultValue={selectedOrder.theoretical_cycle_time_sec} required />
                  </FieldLabel>
                  <button type="submit" className="primary-button" disabled={Object.keys(formErrors.order).length > 0}>
                    {t("Update OF", "Modifier OF")}
                  </button>
                  {actionError("order")}
                  {toast("order")}
                </form>
              </section>
            ) : (
              <div className="empty-state">{t("Select an OF to see and update details.", "Selectionner un OF pour voir et modifier les details.")}</div>
            )}
          </div>
        </Panel>
      );
    }

    if (activeModule === "downtimes") {
      return (
        <Panel
          title={t("Stop qualification", "Qualification arret")}
          subtitle={
            selectedMachine
              ? `${selectedMachineUnqualifiedDowntimes.length} ${t("unqualified for", "non qualifies pour")} ${selectedMachine.code} / ${unqualifiedDowntimes.length} ${t("total", "total")}`
              : `${unqualifiedDowntimes.length} ${t("unqualified downtime(s)", "arret(s) non qualifies")}`
          }
        >
          <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
            >
              <FieldLabel label={t("Downtime to qualify", "Arret a qualifier")} error={fieldError("downtime", "downtime_id")}>
                <select name="downtime_id" required defaultValue={selectedMachineUnqualifiedDowntimes[0]?.id ?? ""}>
                  <option value="" disabled>
                    {t("Select downtime", "Selectionner arret")}
                  </option>
                  {downtimeOptions.map((downtime) => (
                    <option key={downtime.id} value={downtime.id}>
                      {downtimeOptionLabel(downtime)}
                    </option>
                  ))}
                </select>
              </FieldLabel>
              <FieldLabel label={t("Reason", "Cause")} error={fieldError("downtime", "reason_code")}>
                <select name="reason_code" required defaultValue="">
                  <option value="" disabled>
                    {t("Select reason", "Selectionner cause")}
                  </option>
                  {references?.downtime_reasons.map((reason) => (
                    <option key={reason.code} value={reason.code}>
                      {reason.label}
                    </option>
                  ))}
                </select>
              </FieldLabel>
              <FieldLabel label={t("Qualified by", "Qualifie par")} error={fieldError("downtime", "qualified_by")}>
                <input name="qualified_by" placeholder={t("Operator name", "Nom operateur")} required />
              </FieldLabel>
              <FieldLabel label={t("Comment", "Commentaire")}>
                <textarea name="comment" placeholder={t("Optional comment", "Commentaire optionnel")} rows={3} />
              </FieldLabel>
              <button type="submit" className="primary-button" disabled={Object.keys(formErrors.downtime).length > 0}>
                {t("Qualify", "Qualifier")}
              </button>
              {actionError("downtime")}
              {toast("downtime")}
            </form>

            <div className="downtime-board">
              {selectedMachine ? (
                <section className="downtime-focus">
                  <span className="meta-label">{t("Selected machine", "Machine selectionnee")}</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">{t("No unqualified downtime for", "Aucun arret non qualifie pour")} {selectedMachine.code}.</div>
                  )}
                </section>
              ) : null}

              <section>
                <span className="meta-label">{t("All stops waiting qualification", "Tous les arrets en attente de 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">{t("Qualified stops history", "Historique arrets qualifies")}</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 ? `${t("By", "Par")} ${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">{t("No qualified downtime history yet.", "Aucun historique d'arret qualifie.")}</div> : null}
              </section>
            </div>
            {unqualifiedDowntimes.length === 0 ? <div className="empty-state">{t("No downtime currently needs qualification.", "Aucun arret a qualifier actuellement.")}</div> : null}
          </div>
        </Panel>
      );
    }

    if (activeModule === "scrap") {
      return (
        <Panel title={t("Scrap declaration", "Saisie rebut")} subtitle={selectedMachine?.code ?? t("Select machine", "Selectionner 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
            >
              <FieldLabel label={t("Operator", "Operateur")} error={fieldError("scrap", "operator_name")}>
                <input name="operator_name" placeholder={t("Operator name", "Nom operateur")} required />
              </FieldLabel>
              <FieldLabel label={t("Quantity", "Quantite")} error={fieldError("scrap", "quantity")}>
                <input name="quantity" type="number" min="1" placeholder="1" required />
              </FieldLabel>
              <FieldLabel label={t("Scrap reason", "Cause rebut")} error={fieldError("scrap", "reason_code")}>
                <select name="reason_code" required defaultValue="">
                  <option value="" disabled>
                    {t("Select scrap reason", "Selectionner cause rebut")}
                  </option>
                  {references?.scrap_reasons.map((reason) => (
                    <option key={reason.code} value={reason.code}>
                      {reason.label}
                    </option>
                  ))}
                </select>
              </FieldLabel>
              <FieldLabel label={t("Comment", "Commentaire")}>
                <textarea name="comment" placeholder={t("Optional comment", "Commentaire optionnel")} rows={3} />
              </FieldLabel>
              <button type="submit" className="primary-button" disabled={!selectedMachine || Object.keys(formErrors.scrap).length > 0}>
                {t("Record", "Enregistrer")}
              </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">{t("No scrap has been declared yet.", "Aucun rebut declare pour le moment.")}</div> : null}
          </div>
        </Panel>
      );
    }

    return (
      <Panel title={t("Machine config", "Config machine")} subtitle={selectedMachine?.code ?? t("No machine selected", "Aucune machine selectionnee")}>
        {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
          >
            <FieldLabel label={t("Display name", "Nom affiche")} error={fieldError("config", "name")}>
              <input name="name" defaultValue={selectedMachine.config.name} required />
            </FieldLabel>
            <FieldLabel label={t("Brand", "Marque")}>
              <input name="brand" defaultValue={selectedMachine.config.brand ?? ""} />
            </FieldLabel>
            <FieldLabel label={t("Model", "Modele")}>
              <input name="model" defaultValue={selectedMachine.config.model ?? ""} />
            </FieldLabel>
            <label className="checkbox-field">
              <input name="is_active" type="checkbox" defaultChecked={selectedMachine.config.is_active} />
              <span>{t("Active on dashboard", "Active sur tableau de bord")}</span>
            </label>
            <FieldLabel label={t("Cycle signal edge", "Front signal cycle")}>
              <select name="cycle_signal_edge" defaultValue={selectedMachine.config.cycle_signal_edge}>
                <option value="rising">{t("Rising edge", "Front montant")}</option>
                <option value="falling">{t("Falling edge", "Front descendant")}</option>
              </select>
            </FieldLabel>
            <FieldLabel label={t("Debounce", "Anti-rebond")} error={fieldError("config", "debounce_ms")}>
              <input name="debounce_ms" type="number" min="0" defaultValue={selectedMachine.config.debounce_ms} required />
            </FieldLabel>
            <FieldLabel label={t("Minimum cycle time", "Temps cycle minimum")} error={fieldError("config", "min_cycle_time_sec")}>
              <input name="min_cycle_time_sec" type="number" min="1" defaultValue={selectedMachine.config.min_cycle_time_sec} required />
            </FieldLabel>
            <FieldLabel label={t("Maximum cycle time", "Temps cycle maximum")} error={fieldError("config", "max_cycle_time_sec")}>
              <input name="max_cycle_time_sec" type="number" min="1" defaultValue={selectedMachine.config.max_cycle_time_sec} required />
            </FieldLabel>
            <FieldLabel label={t("Stop detection delay", "Delai detection arret")} error={fieldError("config", "stop_detection_delay_sec")}>
              <input name="stop_detection_delay_sec" type="number" min="1" defaultValue={selectedMachine.config.stop_detection_delay_sec} required />
            </FieldLabel>
            <button type="submit" className="primary-button" disabled={Object.keys(formErrors.config).length > 0}>
              {t("Save", "Enregistrer")}
            </button>
            {actionError("config")}
            {toast("config")}
          </form>
        ) : (
          <p>{t("No machine selected.", "Aucune machine selectionnee.")}</p>
        )}
      </Panel>
    );
  }

  if (showSplash) {
    return (
      <div className="splash-screen" aria-label="Plast Track">
        <img src="/KSS.png" alt="KSS" />
      </div>
    );
  }

  return (
    <div className={`app-shell ${isWorkshopMode && activeModule === "atelier" ? "app-shell--workshop" : ""}`}>
      <main className="workspace">
        <aside className="demo-notice" role="note">
          <strong>Simulation et demonstration uniquement</strong>
        </aside>

        <header className="hero">
          <div className="brand-lockup">
            <img className="brand-lockup__logo" src="/KSS.png" alt="KSS" />
            <div>
              <p className="eyebrow">Plast Track MVP</p>
              <h1>{t("Workshop supervision", "Supervision atelier")}</h1>
            </div>
          </div>
          <div className="hero__controls">
            <label className="language-select">
              <span>{t("Language", "Langue")}</span>
              <select value={language} onChange={(event) => setLanguage(event.target.value as Language)}>
                <option value="en">English</option>
                <option value="fr">Francais</option>
              </select>
            </label>
            <div className="hero__status">
              <span className="hero__dot" aria-hidden="true" />
              <strong>{connectionLabel(connectionStatus)}</strong>
              {errorMessage ? <p>{errorMessage}</p> : null}
            </div>
          </div>
        </header>

        {connectionStatus === "Reconnecting" ? <div className="connection-banner">{t("Reconnecting...", "Reconnexion...")}</div> : null}

        <section className="summary-ribbon" aria-label={t("Workshop summary", "Resume atelier")}>
          <KpiBlock label={t("Global OEE", "TRS global")} value={`${summaryMetrics.oee}%`} subLabel={t("Daily aggregate", "Agregat journalier")} tone="dark" />
          <KpiBlock label={t("Production", "Production")} value={summaryMetrics.production} subLabel={`${machines.length} ${t("machines monitored", "machines supervisees")}`} />
          <KpiBlock label={t("Open stops", "Arrets ouverts")} value={summaryMetrics.openDowntimes} subLabel={`${summaryMetrics.unqualifiedDowntimes} ${t("unqualified", "non qualifies")}`} />
          <KpiBlock label={t("Output / scrap", "Production / rebut")} value={`${summaryMetrics.producedQty} / ${summaryMetrics.scrapQty}`} subLabel={t("Pieces today", "Pieces du jour")} />
        </section>

        <nav className="module-tabs" aria-label={t("Modules", "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>
  );
}
