const equipmentId = document.body.dataset.equipmentId;

const endpoints = {
    latest:
        `/equipment/${encodeURIComponent(equipmentId)}/measurements/latest`,
    history:
        `/equipment/${encodeURIComponent(equipmentId)}/measurements/history`,
    analysis:
        `/equipment/${encodeURIComponent(equipmentId)}/analysis`,
    profile:
        `/equipment/${encodeURIComponent(equipmentId)}/profile`,
    brainHistory:
        `/equipment/${encodeURIComponent(equipmentId)}/brain/history`,
    brainTrend:
        `/equipment/${encodeURIComponent(equipmentId)}/brain/trend`,
};

const translations = {
    en: {
        "brand.subtitle": "Equipment Intelligence",
        "global.back_fleet": "Fleet console",
        "light.kicker": "Equipment status",
        "light.title": "See the essential first. Open details only when needed.",
        "light.badge": "Simplified view",
        "nav.overview": "Overview",
        "nav.analysis": "Analysis",
        "nav.live": "Live Data",
        "nav.profile": "Equipment Profile",
        "nav.history": "History",
        "nav.maintenance": "Maintenance",
        "nav.alarms": "Alarms",
        "nav.users": "Users",
        "nav.fleet": "Fleet overview",
        "status.online": "Sentinel online",
        "header.equipment": "Monitored equipment",
        "header.device": "Device",
        "header.last_update": "Last update",
        "header.language": "Language",
        "overview.kicker": "Client overview",
        "overview.title": "Equipment status",
        "overview.health": "Equipment Health",
        "overview.risk": "Risk level",
        "overview.prediction": "Prediction",
        "overview.action": "Recommended action",
        "overview.action_note": "Based on the current analysis",
        "overview.cause": "Most likely cause",
        "overview.report": "Sentinel summary",
        "overview.view_details": "View analysis",
        "analysis.kicker": "Sentinel Brain",
        "analysis.title": "Why Sentinel reached this conclusion",
        "analysis.assessment": "Current assessment",
        "analysis.root_cause": "Most likely cause",
        "analysis.confidence": "Confidence",
        "analysis.health_areas": "Health areas",
        "analysis.thermal": "Thermal",
        "analysis.electrical": "Electrical",
        "analysis.cooling": "Cooling",
        "analysis.sensors": "Sensors",
        "analysis.findings": "Technical findings",
        "live.kicker": "Real-time data",
        "live.title": "Current measurements",
        "live.internal": "Internal",
        "live.ambient": "Ambient",
        "live.evaporator": "Evaporator",
        "live.compressor": "Compressor",
        "live.current": "Current",
        "live.chart": "Temperature history",
        "profile.title": "Normal behavior of this equipment",
        "profile.internal": "Normal internal temperature",
        "profile.compressor": "Normal compressor temperature",
        "profile.current": "Normal compressor current",
        "profile.delta": "Normal cooling difference",
        "profile.run": "Average run time",
        "profile.rest": "Average rest time",
        "profile.samples": "Samples used",
        "history.kicker": "Brain Memory",
        "history.title": "Health history",
        "history.diagnostics": "Stored diagnostics",
        "history.first": "First Health Score",
        "history.current": "Current Health Score",
        "history.change": "Health change",
        "history.chart": "Health Score evolution",
        "history.timeline": "Brain timeline",
        "maintenance.kicker": "Technical tools",
        "maintenance.title": "Maintenance",
        "maintenance.calibration": "Calibration",
        "maintenance.calibration_text":
            "Compare Sentinel sensors with a reference probe.",
        "maintenance.sensors": "Sensors",
        "maintenance.sensors_text":
            "Review sensor health and detected signal issues.",
        "maintenance.diagnostics": "Diagnostics",
        "maintenance.diagnostics_text":
            "Check acquisition, database and Brain services.",
        "maintenance.backup": "Backup",
        "maintenance.backup_text":
            "Export configuration, databases and logs.",
        "alarms.kicker": "Alarm management",
        "alarms.title": "Alarms",
        "alarms.no_active": "No active alarms",
        "alarms.active": "Active alarms",
        "alarms.active_help": "Requires attention now",
        "alarms.awaiting_ack": "Awaiting acknowledgement",
        "alarms.awaiting_ack_help": "Waiting for a user response",
        "alarms.escalated": "Escalated",
        "alarms.escalated_help": "Sent to the next contact",
        "alarms.history": "Alarm history",
        "alarms.history_help": "Recorded alarm events",
        "alarms.current_state": "Current state",
        "alarms.all_clear": "Everything is clear.",
        "alarms.all_clear_text":
            "Sentinel has no active alarm for this equipment.",
        "alarms.escalation": "Escalation",
        "alarms.escalation_title": "Automatic notification chain",
        "alarms.contact_primary": "Primary contact",
        "alarms.email_sms": "Email / SMS",
        "alarms.ack": "Acknowledgement",
        "alarms.wait_delay": "Wait configured delay",
        "alarms.next_contact": "Next contact",
        "alarms.if_no_ack": "If not acknowledged",
        "alarms.foundation": "Architecture ready",
        "alarms.foundation_text":
            "Email, SMS, acknowledgement, delays, groups and escalation rules will use this page.",
        "alarms.recent": "Recent alarms",
        "alarms.recent_title": "Alarm events",
        "alarms.configure": "Configure",
        "alarms.no_history": "No alarm has been recorded yet.",
        "users.kicker": "Access management",
        "users.title": "Users",
        "users.local_mode": "Local prototype",
        "users.access_model": "Access model",
        "users.access_title": "One interface, different responsibilities.",
        "users.access_text":
            "User and group access are managed centrally from the Administration workspace.",
        "users.auth": "Authentication",
        "users.not_enabled": "Managed centrally",
        "users.admin": "Admin",
        "users.admin_scope": "Full platform access",
        "users.admin_1": "Manage organizations and sites",
        "users.admin_2": "Manage users and permissions",
        "users.admin_3": "Configure alarms and system settings",
        "users.manager": "Manager",
        "users.manager_scope": "Operational overview",
        "users.manager_1": "View fleet health and reports",
        "users.manager_2": "Acknowledge alarms",
        "users.manager_3": "Review maintenance recommendations",
        "users.technician": "Technician",
        "users.technician_scope": "Technical operations",
        "users.technician_1": "Access technical analysis",
        "users.technician_2": "Calibration and diagnostics",
        "users.technician_3": "Record maintenance actions",
        "users.read_only": "Read only",
        "users.read_only_scope": "View access",
        "users.read_only_1": "View equipment health",
        "users.read_only_2": "View live data and history",
        "users.read_only_3": "No configuration changes",
        "users.directory": "User directory",
        "users.directory_title": "Configured users",
        "users.add": "Add user",
        "users.no_users":
            "User accounts will appear here when authentication is enabled.",
    },

    fr: {
        "brand.subtitle": "Intelligence des équipements",
        "global.back_fleet": "Console flotte",
        "light.kicker": "État de l’équipement",
        "light.title": "Voir l’essentiel d’abord. Ouvrir le détail seulement si nécessaire.",
        "light.badge": "Vue simplifiée",
        "nav.overview": "Vue générale",
        "nav.analysis": "Analyse",
        "nav.live": "Données en direct",
        "nav.profile": "Profil équipement",
        "nav.history": "Historique",
        "nav.maintenance": "Maintenance",
        "nav.alarms": "Alarmes",
        "nav.users": "Utilisateurs",
        "nav.fleet": "Vue de la flotte",
        "status.online": "Sentinel en ligne",
        "header.equipment": "Équipement surveillé",
        "header.device": "Boîtier",
        "header.last_update": "Dernière mise à jour",
        "header.language": "Langue",
        "overview.kicker": "Vue client",
        "overview.title": "État de l’équipement",
        "overview.health": "Santé de l’équipement",
        "overview.risk": "Niveau de risque",
        "overview.prediction": "Prévision",
        "overview.action": "Action recommandée",
        "overview.action_note": "Selon l’analyse actuelle",
        "overview.cause": "Cause la plus probable",
        "overview.report": "Résumé Sentinel",
        "overview.view_details": "Voir l’analyse",
        "analysis.kicker": "Sentinel Brain",
        "analysis.title": "Pourquoi Sentinel arrive à cette conclusion",
        "analysis.assessment": "Évaluation actuelle",
        "analysis.root_cause": "Cause la plus probable",
        "analysis.confidence": "Confiance",
        "analysis.health_areas": "Domaines de santé",
        "analysis.thermal": "Thermique",
        "analysis.electrical": "Électrique",
        "analysis.cooling": "Froid",
        "analysis.sensors": "Capteurs",
        "analysis.findings": "Constats techniques",
        "live.kicker": "Données temps réel",
        "live.title": "Mesures actuelles",
        "live.internal": "Interne",
        "live.ambient": "Ambiante",
        "live.evaporator": "Évaporateur",
        "live.compressor": "Compresseur",
        "live.current": "Courant",
        "live.chart": "Historique des températures",
        "profile.title": "Comportement normal de cet équipement",
        "profile.internal": "Température interne normale",
        "profile.compressor": "Température compresseur normale",
        "profile.current": "Courant compresseur normal",
        "profile.delta": "Écart de froid normal",
        "profile.run": "Durée moyenne de marche",
        "profile.rest": "Durée moyenne de repos",
        "profile.samples": "Mesures utilisées",
        "history.kicker": "Mémoire du Brain",
        "history.title": "Historique de santé",
        "history.diagnostics": "Diagnostics enregistrés",
        "history.first": "Premier Health Score",
        "history.current": "Health Score actuel",
        "history.change": "Évolution de santé",
        "history.chart": "Évolution du Health Score",
        "history.timeline": "Chronologie du Brain",
        "maintenance.kicker": "Outils techniques",
        "maintenance.title": "Maintenance",
        "maintenance.calibration": "Calibration",
        "maintenance.calibration_text":
            "Comparer les sondes Sentinel avec une sonde de référence.",
        "maintenance.sensors": "Capteurs",
        "maintenance.sensors_text":
            "Consulter la santé des capteurs et les anomalies de signal.",
        "maintenance.diagnostics": "Diagnostics",
        "maintenance.diagnostics_text":
            "Vérifier l’acquisition, la base et les services du Brain.",
        "maintenance.backup": "Sauvegarde",
        "maintenance.backup_text":
            "Exporter la configuration, les bases et les journaux.",
        "alarms.kicker": "Gestion des alarmes",
        "alarms.title": "Alarmes",
        "alarms.no_active": "Aucune alarme active",
        "alarms.active": "Alarmes actives",
        "alarms.active_help": "Nécessitent une attention immédiate",
        "alarms.awaiting_ack": "En attente d’acquittement",
        "alarms.awaiting_ack_help": "En attente de réponse d’un utilisateur",
        "alarms.escalated": "Escaladées",
        "alarms.escalated_help": "Transmises au contact suivant",
        "alarms.history": "Historique des alarmes",
        "alarms.history_help": "Événements d’alarme enregistrés",
        "alarms.current_state": "État actuel",
        "alarms.all_clear": "Tout est normal.",
        "alarms.all_clear_text":
            "Sentinel ne détecte aucune alarme active sur cet équipement.",
        "alarms.escalation": "Escalade",
        "alarms.escalation_title": "Chaîne automatique de notification",
        "alarms.contact_primary": "Contact principal",
        "alarms.email_sms": "E-mail / SMS",
        "alarms.ack": "Acquittement",
        "alarms.wait_delay": "Attente du délai configuré",
        "alarms.next_contact": "Contact suivant",
        "alarms.if_no_ack": "Si aucune confirmation",
        "alarms.foundation": "Architecture prête",
        "alarms.foundation_text":
            "E-mail, SMS, acquittement, délais, groupes et règles d’escalade utiliseront cette page.",
        "alarms.recent": "Alarmes récentes",
        "alarms.recent_title": "Événements d’alarme",
        "alarms.configure": "Configurer",
        "alarms.no_history": "Aucune alarme n’a encore été enregistrée.",
        "users.kicker": "Gestion des accès",
        "users.title": "Utilisateurs",
        "users.local_mode": "Prototype local",
        "users.access_model": "Modèle d’accès",
        "users.access_title": "Une interface, plusieurs responsabilités.",
        "users.access_text":
            "Les utilisateurs et accès par groupe sont gérés depuis l’espace Administration central.",
        "users.auth": "Authentification",
        "users.not_enabled": "Géré centralement",
        "users.admin": "Administrateur",
        "users.admin_scope": "Accès complet à la plateforme",
        "users.admin_1": "Gérer les organisations et les sites",
        "users.admin_2": "Gérer les utilisateurs et les droits",
        "users.admin_3": "Configurer les alarmes et le système",
        "users.manager": "Responsable",
        "users.manager_scope": "Vue opérationnelle",
        "users.manager_1": "Consulter la santé de la flotte et les rapports",
        "users.manager_2": "Acquitter les alarmes",
        "users.manager_3": "Consulter les recommandations de maintenance",
        "users.technician": "Technicien",
        "users.technician_scope": "Opérations techniques",
        "users.technician_1": "Accéder aux analyses techniques",
        "users.technician_2": "Calibration et diagnostics",
        "users.technician_3": "Enregistrer les interventions de maintenance",
        "users.read_only": "Lecture seule",
        "users.read_only_scope": "Consultation uniquement",
        "users.read_only_1": "Consulter la santé des équipements",
        "users.read_only_2": "Consulter les données et l’historique",
        "users.read_only_3": "Aucune modification de configuration",
        "users.directory": "Répertoire utilisateurs",
        "users.directory_title": "Utilisateurs configurés",
        "users.add": "Ajouter un utilisateur",
        "users.no_users":
            "Les comptes utilisateurs apparaîtront ici lorsque l’authentification sera activée.",
    },
};

let currentLanguage =
    localStorage.getItem("sentinel-language") || "en";

let historyLimit = 720;
let temperatureChart = null;
let healthChart = null;


function setText(id, value) {
    const element = document.getElementById(id);

    if (element) {
        element.textContent = value;
    }
}


function formatNumber(value, decimals = 2) {
    const number = Number(value);
    return Number.isFinite(number)
        ? number.toFixed(decimals)
        : "—";
}


function formatTimestamp(value) {
    if (!value) {
        return "—";
    }

    const normalized = value.includes("T")
        ? value
        : `${value.replace(" ", "T")}Z`;

    const date = new Date(normalized);

    if (Number.isNaN(date.getTime())) {
        return value;
    }

    return new Intl.DateTimeFormat(
        currentLanguage === "fr" ? "fr-FR" : "en-GB",
        {
            day: "2-digit",
            month: "short",
            hour: "2-digit",
            minute: "2-digit",
        }
    ).format(date);
}


function applyLanguage(language) {
    currentLanguage = language;
    localStorage.setItem("sentinel-language", language);
    document.documentElement.lang = language;

    document
        .querySelectorAll("[data-i18n]")
        .forEach(element => {
            const key = element.dataset.i18n;
            const value = translations[language]?.[key];

            if (value) {
                element.textContent = value;
            }
        });

    document.getElementById("language-selector").value = language;
}


function showTab(tabName) {
    document
        .querySelectorAll(".nav-item")
        .forEach(item => {
            item.classList.toggle(
                "active",
                item.dataset.tab === tabName
            );
        });

    document
        .querySelectorAll(".tab-panel")
        .forEach(panel => {
            panel.classList.toggle(
                "active",
                panel.dataset.panel === tabName
            );
        });

    localStorage.setItem("sentinel-active-tab", tabName);

    window.setTimeout(() => {
        temperatureChart?.resize();
        healthChart?.resize();
    }, 100);
}


function riskLabel(riskIndex) {
    if (riskIndex < 10) {
        return currentLanguage === "fr"
            ? "Très faible"
            : "Very low";
    }

    if (riskIndex < 25) {
        return currentLanguage === "fr"
            ? "Faible"
            : "Low";
    }

    if (riskIndex < 50) {
        return currentLanguage === "fr"
            ? "Modéré"
            : "Moderate";
    }

    if (riskIndex < 75) {
        return currentLanguage === "fr"
            ? "Élevé"
            : "High";
    }

    return currentLanguage === "fr"
        ? "Critique"
        : "Critical";
}


function simpleSummary(analysis) {
    const healthy =
        Number(analysis.health_score) >= 90
        && Number(analysis.risk_index ?? 0) < 15;

    if (healthy) {
        return {
            title:
                currentLanguage === "fr"
                    ? "Tout fonctionne normalement."
                    : "Everything is working normally.",
            text:
                currentLanguage === "fr"
                    ? "Le froid, la charge électrique et les capteurs correspondent au comportement habituel de cet équipement."
                    : "Cooling, electrical load and sensor readings match the usual behavior of this equipment.",
        };
    }

    return {
        title:
            currentLanguage === "fr"
                ? "Une dérive doit être surveillée."
                : "A change needs monitoring.",
        text:
            currentLanguage === "fr"
                ? "Consultez l’onglet Analyse pour comprendre la cause probable et l’action recommandée."
                : "Open the Analysis tab to review the likely cause and recommended action.",
    };
}


const brainText = {
    en: {
        status: {EXCELLENT: "Excellent", SURVEILLANCE: "Monitoring", ATTENTION: "Attention", CRITICAL: "Critical", UNKNOWN: "Unknown"},
        analysis: {
            EXCELLENT: "Historical behavior remains stable and consistent with this equipment's baseline.",
            SURVEILLANCE: "A minor change has been detected and should be monitored.",
            ATTENTION: "A significant change has been detected and requires attention.",
            CRITICAL: "A critical change has been detected and requires technical inspection."
        },
        recommendation: {
            EXCELLENT: "No action required.",
            SURVEILLANCE: "Continue monitoring the next operating cycles.",
            ATTENTION: "Inspect the affected measurements and equipment condition.",
            CRITICAL: "Technical inspection is recommended immediately."
        },
        rootCause: {
            NO_ANOMALY_DETECTED: "No anomaly detected.",
            SENSOR_INSTRUMENTATION_FAULT: "Probable sensor or instrumentation fault.",
            COMPRESSOR_EFFICIENCY_DEGRADATION: "Probable compressor efficiency degradation.",
            POOR_HEAT_REJECTION: "Probable condenser airflow or heat rejection issue.",
            EXTERNAL_THERMAL_LOAD: "Probable external thermal load or door event.",
            REFRIGERATION_PERFORMANCE_DEGRADATION: "Probable refrigeration performance degradation.",
            ELECTRICAL_OR_MECHANICAL_LOAD_INCREASE: "Probable electrical or mechanical load increase.",
            UNCLASSIFIED_DEVIATION: "Unclassified equipment deviation."
        },
        rootExplanation: {
            NO_ANOMALY_DETECTED: "Thermal, electrical, cooling and sensor indicators remain stable and consistent with this equipment's baseline.",
            SENSOR_INSTRUMENTATION_FAULT: "One or more sensor signals appear missing, frozen or implausible.",
            COMPRESSOR_EFFICIENCY_DEGRADATION: "Compressor temperature and electrical load are increasing while cooling performance deviates from baseline.",
            POOR_HEAT_REJECTION: "The compressor is running hotter than usual without a matching electrical increase.",
            EXTERNAL_THERMAL_LOAD: "Internal temperature is rising without a matching refrigeration-system degradation pattern.",
            REFRIGERATION_PERFORMANCE_DEGRADATION: "Cooling performance is deviating from this equipment's normal behavior.",
            ELECTRICAL_OR_MECHANICAL_LOAD_INCREASE: "Electrical or mechanical effort is higher than this equipment's normal behavior.",
            UNCLASSIFIED_DEVIATION: "Sentinel detected a deviation that does not yet match a known failure pattern."
        }
    },
    fr: {
        status: {EXCELLENT: "Excellent", SURVEILLANCE: "Surveillance", ATTENTION: "Attention", CRITICAL: "Critique", UNKNOWN: "Inconnu"},
        analysis: {
            EXCELLENT: "Le comportement historique reste stable et cohérent avec la référence propre à cet équipement.",
            SURVEILLANCE: "Une légère dérive a été détectée et doit être surveillée.",
            ATTENTION: "Une dérive significative a été détectée et nécessite une attention.",
            CRITICAL: "Une dérive critique a été détectée et nécessite une inspection technique."
        },
        recommendation: {
            EXCELLENT: "Aucune action nécessaire.",
            SURVEILLANCE: "Poursuivre la surveillance des prochains cycles de fonctionnement.",
            ATTENTION: "Contrôler les mesures concernées et l'état de l'équipement.",
            CRITICAL: "Une inspection technique immédiate est recommandée."
        },
        rootCause: {
            NO_ANOMALY_DETECTED: "Aucune anomalie détectée.",
            SENSOR_INSTRUMENTATION_FAULT: "Défaut probable d'un capteur ou de l'instrumentation.",
            COMPRESSOR_EFFICIENCY_DEGRADATION: "Dégradation probable de l'efficacité du compresseur.",
            POOR_HEAT_REJECTION: "Problème probable de ventilation du condenseur ou d'évacuation thermique.",
            EXTERNAL_THERMAL_LOAD: "Charge thermique externe ou événement de porte probable.",
            REFRIGERATION_PERFORMANCE_DEGRADATION: "Dégradation probable des performances frigorifiques.",
            ELECTRICAL_OR_MECHANICAL_LOAD_INCREASE: "Augmentation probable de la charge électrique ou mécanique.",
            UNCLASSIFIED_DEVIATION: "Dérive de l'équipement non encore classifiée."
        },
        rootExplanation: {
            NO_ANOMALY_DETECTED: "Les indicateurs thermiques, électriques, frigorifiques et les capteurs restent stables et cohérents avec la référence de cet équipement.",
            SENSOR_INSTRUMENTATION_FAULT: "Un ou plusieurs signaux de capteurs semblent absents, figés ou incohérents.",
            COMPRESSOR_EFFICIENCY_DEGRADATION: "La température et la charge électrique du compresseur augmentent tandis que les performances frigorifiques s'écartent de la référence.",
            POOR_HEAT_REJECTION: "Le compresseur fonctionne plus chaud que d'habitude sans augmentation électrique équivalente.",
            EXTERNAL_THERMAL_LOAD: "La température interne augmente sans profil correspondant à une dégradation du système frigorifique.",
            REFRIGERATION_PERFORMANCE_DEGRADATION: "Les performances frigorifiques s'écartent du comportement normal de cet équipement.",
            ELECTRICAL_OR_MECHANICAL_LOAD_INCREASE: "L'effort électrique ou mécanique est supérieur au comportement normal de cet équipement.",
            UNCLASSIFIED_DEVIATION: "Sentinel a détecté une dérive qui ne correspond pas encore à un mode de panne connu."
        }
    }
};

function localizedStatus(status) {
    return brainText[currentLanguage]?.status?.[status] ?? status ?? "—";
}

function localizedAnalysis(analysis) {
    return brainText[currentLanguage]?.analysis?.[analysis.status] ?? analysis.analysis ?? "—";
}

function localizedRecommendation(analysis) {
    return brainText[currentLanguage]?.recommendation?.[analysis.status] ?? analysis.recommendation ?? "—";
}

function localizedRootCause(analysis) {
    const code = analysis.root_cause_code || (analysis.status === "EXCELLENT" ? "NO_ANOMALY_DETECTED" : "UNCLASSIFIED_DEVIATION");
    return brainText[currentLanguage]?.rootCause?.[code] ?? analysis.root_cause ?? "—";
}

function localizedRootExplanation(analysis) {
    const code = analysis.root_cause_code || (analysis.status === "EXCELLENT" ? "NO_ANOMALY_DETECTED" : "UNCLASSIFIED_DEVIATION");
    return brainText[currentLanguage]?.rootExplanation?.[code] ?? analysis.root_cause_explanation ?? "—";
}

function localizedFindingTitle(code) {
    const words = String(code || "").replaceAll("_", " ").toLowerCase();
    if (currentLanguage !== "fr") return words.replace(/\b\w/g, c => c.toUpperCase());
    const exact = {
        EVAPORATOR_DELTA_BASELINE_OK: "Écart évaporateur conforme à la référence",
        EVAPORATOR_DELTA_STABLE: "Écart évaporateur stable",
        COOLING_EFFORT_BASELINE_OK: "Effort frigorifique conforme à la référence",
        INTERNAL_TEMP_STABLE: "Température interne stable",
        INTERNAL_TEMP_STABILITY_OK: "Stabilité de la température interne correcte",
        COMPRESSOR_TEMP_STABLE: "Température compresseur stable",
        COMPRESSOR_CURRENT_STABLE: "Courant compresseur stable",
        INTERNAL_TEMP_BASELINE_OK: "Température interne conforme à la référence",
        COMPRESSOR_TEMP_BASELINE_OK: "Température compresseur conforme à la référence",
        COMPRESSOR_CURRENT_BASELINE_OK: "Courant compresseur conforme à la référence",
        SENSOR_HEALTH_OK: "Capteurs en bon état",
        COOLING_DATA_INSUFFICIENT: "Données frigorifiques insuffisantes"
    };
    return exact[code] ?? String(code || "").replaceAll("_", " ");
}

function localizedFindingExplanation(finding) {
    if (currentLanguage !== "fr") return finding.explanation;
    const exact = {
        EVAPORATOR_DELTA_BASELINE_OK: "L'écart entre la température interne et l'évaporateur reste cohérent avec la référence de cet équipement.",
        EVAPORATOR_DELTA_STABLE: "L'écart de température frigorifique reste stable.",
        COOLING_EFFORT_BASELINE_OK: "L'effort thermique et électrique du compresseur reste cohérent avec la référence de l'équipement.",
        INTERNAL_TEMP_STABLE: "La température interne reste stable.",
        INTERNAL_TEMP_STABILITY_OK: "La stabilité de la température interne est conforme au comportement attendu.",
        COMPRESSOR_TEMP_STABLE: "La température du compresseur reste stable.",
        COMPRESSOR_CURRENT_STABLE: "Le courant du compresseur reste stable.",
        INTERNAL_TEMP_BASELINE_OK: "La température interne reste cohérente avec la référence de cet équipement.",
        COMPRESSOR_TEMP_BASELINE_OK: "La température du compresseur reste cohérente avec la référence de cet équipement.",
        COMPRESSOR_CURRENT_BASELINE_OK: "Le courant du compresseur reste cohérent avec la référence de cet équipement.",
        SENSOR_HEALTH_OK: "Les signaux des capteurs sont cohérents et exploitables.",
        COOLING_DATA_INSUFFICIENT: "Il n'y a pas encore assez de données pour évaluer correctement les performances frigorifiques."
    };
    return exact[finding.code] ?? `Constat technique : ${localizedFindingTitle(finding.code).toLowerCase()}.`;
}


function updateFindings(findings) {
    const grid = document.getElementById("findings-grid");

    if (!grid) {
        return;
    }

    setText("findings-count", findings.length);
    grid.innerHTML = "";

    findings.forEach(finding => {
        const card = document.createElement("article");
        card.className = "finding-card card";

        card.innerHTML = `
            <div class="finding-head">
                <span class="finding-severity">
                    ${finding.severity}
                </span>
                <strong>
                    ${Math.round(finding.confidence)}%
                </strong>
            </div>
            <h4>
                ${localizedFindingTitle(finding.code)}
            </h4>
            <p>${localizedFindingExplanation(finding)}</p>
            <small>
                ${formatNumber(finding.value, 4)}
                ${finding.unit}
            </small>
        `;

        grid.appendChild(card);
    });
}


async function refreshLatest() {
    try {
        const response = await fetch(
            `${endpoints.latest}?t=${Date.now()}`,
            {cache: "no-store"}
        );

        if (!response.ok) {
            throw new Error(`Latest HTTP ${response.status}`);
        }

        const measurement = await response.json();

        setText(
            "internal-temperature",
            formatNumber(measurement.internal_temperature_c)
        );
        setText(
            "ambient-temperature",
            formatNumber(measurement.ambient_temperature_c)
        );
        setText(
            "evaporator-temperature",
            formatNumber(measurement.evaporator_temperature_c)
        );
        setText(
            "compressor-temperature",
            formatNumber(measurement.compressor_temperature_c)
        );
        setText(
            "compressor-current",
            formatNumber(measurement.compressor_current_a, 3)
        );
        setText("device-id", measurement.device_id);
        setText("recorded-at", formatTimestamp(measurement.recorded_at));
        setText(
            "sidebar-connection",
            currentLanguage === "fr"
                ? "Réception des données"
                : "Receiving data"
        );
    } catch (error) {
        console.error(error);
        setText(
            "sidebar-connection",
            currentLanguage === "fr"
                ? "Connexion perdue"
                : "Connection lost"
        );
    }
}


async function refreshAnalysis() {
    try {
        const response = await fetch(
            `${endpoints.analysis}?t=${Date.now()}`,
            {cache: "no-store"}
        );

        if (!response.ok) {
            throw new Error(`Analysis HTTP ${response.status}`);
        }

        const analysis = await response.json();
        const health = Math.round(Number(analysis.health_score));
        const risk = Number(analysis.risk_index ?? 0);
        const summary = simpleSummary(analysis);

        setText("health-score", health);
        setText("health-label", localizedStatus(analysis.status));
        setText("header-status", localizedStatus(analysis.status));
        setText("overview-summary", localizedAnalysis(analysis));
        setText("risk-level", riskLabel(risk));
        setText("risk-index", `${formatNumber(risk, 1)}%`);

        setText(
            "overview-prediction",
            analysis.prediction_horizon_days
                ? `${analysis.prediction_horizon_days} days`
                : (
                    currentLanguage === "fr"
                        ? "Aucune alerte à court terme"
                        : "No near-term warning"
                )
        );

        setText(
            "prediction-confidence",
            analysis.prediction_confidence === null
                || analysis.prediction_confidence === undefined
                ? "—"
                : `${Math.round(analysis.prediction_confidence)}%`
        );

        setText("overview-action", localizedRecommendation(analysis));
        setText(
            "overview-cause",
            localizedRootCause(analysis)
        );
        setText(
            "overview-cause-confidence",
            `${Math.round(analysis.root_cause_confidence ?? 0)}%`
        );

        setText("simple-report-title", summary.title);
        setText("simple-report-text", summary.text);

        setText("brain-analysis", localizedAnalysis(analysis));
        setText(
            "root-cause",
            localizedRootCause(analysis)
        );
        setText(
            "root-cause-confidence",
            Math.round(analysis.root_cause_confidence ?? 0)
        );
        setText(
            "root-cause-explanation",
            localizedRootExplanation(analysis)
        );

        setText(
            "thermal-score",
            `${Math.round(analysis.thermal_score ?? 0)}%`
        );
        setText(
            "electrical-score",
            `${Math.round(analysis.electrical_score ?? 0)}%`
        );
        setText(
            "cooling-score",
            `${Math.round(analysis.cooling_score ?? 0)}%`
        );
        setText(
            "sensor-score",
            `${Math.round(analysis.sensor_score ?? 0)}%`
        );

        updateFindings(analysis.findings ?? []);
    } catch (error) {
        console.error(error);
    }
}


async function refreshProfile() {
    try {
        const response = await fetch(
            `${endpoints.profile}?t=${Date.now()}`,
            {cache: "no-store"}
        );

        if (!response.ok) {
            throw new Error(`Profile HTTP ${response.status}`);
        }

        const profile = await response.json();

        setText(
            "profile-status",
            currentLanguage === "fr"
                ? "Profil disponible"
                : "Profile available"
        );
        setText(
            "profile-internal",
            `${formatNumber(profile.internal_temperature.mean)} °C`
        );
        setText(
            "profile-compressor",
            `${formatNumber(profile.compressor_temperature.mean)} °C`
        );
        setText(
            "profile-current",
            `${formatNumber(profile.compressor_current.mean, 3)} A`
        );
        setText(
            "profile-delta",
            `${formatNumber(profile.evaporator_delta.mean)} °C`
        );
        setText(
            "profile-run",
            profile.cycle_profile.average_run_minutes === null
                ? (
                    currentLanguage === "fr"
                        ? "Non détecté"
                        : "Not detected"
                )
                : `${formatNumber(
                    profile.cycle_profile.average_run_minutes
                )} min`
        );
        setText(
            "profile-rest",
            profile.cycle_profile.average_rest_minutes === null
                ? (
                    currentLanguage === "fr"
                        ? "Non détecté"
                        : "Not detected"
                )
                : `${formatNumber(
                    profile.cycle_profile.average_rest_minutes
                )} min`
        );
        setText("profile-samples", profile.sample_count);
    } catch (error) {
        console.error(error);
        setText(
            "profile-status",
            currentLanguage === "fr"
                ? "Apprentissage"
                : "Learning"
        );
    }
}


function createTemperatureChart(history) {
    const canvas = document.getElementById("temperature-chart");

    temperatureChart = new Chart(canvas, {
        type: "line",
        data: {
            labels: history.map(item =>
                formatTimestamp(item.recorded_at)
            ),
            datasets: [
                {
                    label: "Internal",
                    data: history.map(item =>
                        item.internal_temperature_c
                    ),
                    borderColor: "#66d8ff",
                    pointRadius: 0,
                    borderWidth: 2,
                    tension: 0.2,
                },
                {
                    label: "Evaporator",
                    data: history.map(item =>
                        item.evaporator_temperature_c
                    ),
                    borderColor: "#938cff",
                    pointRadius: 0,
                    borderWidth: 1.6,
                    tension: 0.2,
                },
                {
                    label: "Compressor",
                    data: history.map(item =>
                        item.compressor_temperature_c
                    ),
                    borderColor: "#ff9b62",
                    pointRadius: 0,
                    borderWidth: 1.6,
                    tension: 0.2,
                },
                {
                    label: "Ambient",
                    data: history.map(item =>
                        item.ambient_temperature_c
                    ),
                    borderColor: "#55dda1",
                    pointRadius: 0,
                    borderWidth: 1.4,
                    tension: 0.2,
                },
            ],
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            animation: false,
            interaction: {
                mode: "index",
                intersect: false,
            },
            plugins: {
                legend: {
                    labels: {
                        color: "#bed0de",
                        usePointStyle: true,
                    },
                },
            },
            scales: {
                x: {
                    ticks: {
                        color: "#88a2b7",
                        maxTicksLimit: 8,
                    },
                    grid: {
                        color: "rgba(136, 162, 183, 0.07)",
                    },
                },
                y: {
                    ticks: {
                        color: "#88a2b7",
                    },
                    grid: {
                        color: "rgba(136, 162, 183, 0.07)",
                    },
                },
            },
        },
    });
}


async function refreshTemperatureHistory() {
    try {
        const response = await fetch(
            `${endpoints.history}?limit=${historyLimit}&t=${Date.now()}`,
            {cache: "no-store"}
        );

        if (!response.ok) {
            throw new Error(`History HTTP ${response.status}`);
        }

        const history = await response.json();

        if (!temperatureChart) {
            createTemperatureChart(history);
            return;
        }

        temperatureChart.data.labels = history.map(item =>
            formatTimestamp(item.recorded_at)
        );

        temperatureChart.data.datasets[0].data =
            history.map(item => item.internal_temperature_c);
        temperatureChart.data.datasets[1].data =
            history.map(item => item.evaporator_temperature_c);
        temperatureChart.data.datasets[2].data =
            history.map(item => item.compressor_temperature_c);
        temperatureChart.data.datasets[3].data =
            history.map(item => item.ambient_temperature_c);

        temperatureChart.update("none");
    } catch (error) {
        console.error(error);
    }
}


function createHealthChart(history) {
    const canvas = document.getElementById("health-chart");

    healthChart = new Chart(canvas, {
        type: "line",
        data: {
            labels: history.map(item =>
                formatTimestamp(item.measurement_recorded_at)
            ),
            datasets: [
                {
                    label: "Health Score",
                    data: history.map(item => item.health_score),
                    borderColor: "#55dda1",
                    backgroundColor:
                        "rgba(85, 221, 161, 0.08)",
                    fill: true,
                    pointRadius: 2,
                    borderWidth: 2,
                    tension: 0.25,
                },
            ],
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            animation: false,
            scales: {
                x: {
                    ticks: {
                        color: "#88a2b7",
                        maxTicksLimit: 8,
                    },
                    grid: {
                        color: "rgba(136, 162, 183, 0.07)",
                    },
                },
                y: {
                    min: 0,
                    max: 100,
                    ticks: {
                        color: "#88a2b7",
                    },
                    grid: {
                        color: "rgba(136, 162, 183, 0.07)",
                    },
                },
            },
            plugins: {
                legend: {
                    labels: {
                        color: "#bed0de",
                    },
                },
            },
        },
    });
}


function updateTimeline(history) {
    const container = document.getElementById("brain-timeline");
    container.innerHTML = "";

    history
        .slice(-12)
        .reverse()
        .forEach(item => {
            const row = document.createElement("div");
            row.className = "timeline-item";
            row.innerHTML = `
                <time>
                    ${formatTimestamp(item.measurement_recorded_at)}
                </time>
                <span>
                    Health ${formatNumber(item.health_score, 0)}%
                </span>
                <strong>
                    ${item.root_cause_code ? (brainText[currentLanguage]?.rootCause?.[item.root_cause_code] ?? item.root_cause) : (brainText[currentLanguage]?.analysis?.[item.status] ?? item.analysis)}
                </strong>
            `;
            container.appendChild(row);
        });

    if (!history.length) {
        container.textContent =
            currentLanguage === "fr"
                ? "La mémoire du Brain est encore en apprentissage."
                : "Brain Memory is still learning.";
    }
}


async function refreshBrainHistory() {
    try {
        const [historyResponse, trendResponse] = await Promise.all([
            fetch(
                `${endpoints.brainHistory}?limit=500&t=${Date.now()}`,
                {cache: "no-store"}
            ),
            fetch(
                `${endpoints.brainTrend}?limit=500&t=${Date.now()}`,
                {cache: "no-store"}
            ),
        ]);

        if (!historyResponse.ok || !trendResponse.ok) {
            throw new Error("Brain Memory request failed");
        }

        const history = await historyResponse.json();
        const trend = await trendResponse.json();

        setText("history-count", trend.sample_count ?? 0);
        setText(
            "history-first",
            trend.first_health_score === undefined
                ? "—"
                : `${formatNumber(trend.first_health_score, 1)}%`
        );
        setText(
            "history-current",
            trend.latest_health_score === undefined
                ? "—"
                : `${formatNumber(trend.latest_health_score, 1)}%`
        );
        setText(
            "history-change",
            trend.health_change === undefined
                ? "—"
                : `${formatNumber(trend.health_change, 1)} points`
        );
        setText(
            "history-trend",
            (trend.trend ?? "LEARNING").replaceAll("_", " ")
        );

        if (!healthChart) {
            createHealthChart(history);
        } else {
            healthChart.data.labels = history.map(item =>
                formatTimestamp(item.measurement_recorded_at)
            );
            healthChart.data.datasets[0].data =
                history.map(item => item.health_score);
            healthChart.update("none");
        }

        updateTimeline(history);
    } catch (error) {
        console.error(error);
    }
}


document
    .querySelectorAll(".nav-item")
    .forEach(item => {
        item.addEventListener("click", () => {
            showTab(item.dataset.tab);
        });
    });


document
    .querySelectorAll("[data-open-tab]")
    .forEach(button => {
        button.addEventListener("click", () => {
            showTab(button.dataset.openTab);
        });
    });


document
    .getElementById("language-selector")
    .addEventListener("change", event => {
        applyLanguage(event.target.value);
        refreshLatest();
        refreshAnalysis();
        refreshProfile();
        refreshBrainHistory();
    });


[
    ["period-120", 120],
    ["period-720", 720],
    ["period-5000", 5000],
].forEach(([id, limit]) => {
    document
        .getElementById(id)
        .addEventListener("click", async event => {
            historyLimit = limit;

            document
                .querySelectorAll(".chart-actions .small-button")
                .forEach(button =>
                    button.classList.remove("active")
                );

            event.currentTarget.classList.add("active");
            await refreshTemperatureHistory();
        });
});


document
    .getElementById("reset-zoom")
    .addEventListener("click", () => {
        temperatureChart?.reset();
    });


applyLanguage(currentLanguage);
showTab(
    localStorage.getItem("sentinel-active-tab")
    || "overview"
);

refreshLatest();
refreshAnalysis();
refreshProfile();
refreshTemperatureHistory();
refreshBrainHistory();

window.setInterval(refreshLatest, 5000);
window.setInterval(refreshAnalysis, 10000);
window.setInterval(refreshTemperatureHistory, 15000);
window.setInterval(refreshBrainHistory, 30000);


// Sentinel V6 maintenance actions.
async function v6ApiRequest(url, options = {}) {
    const response = await fetch(url, {
        headers: {"Content-Type": "application/json"},
        ...options,
    });
    if (!response.ok) {
        let message = `HTTP ${response.status}`;
        try { message = (await response.json()).detail || message; } catch (_) {}
        throw new Error(message);
    }
    return response.json();
}

document.getElementById("calibration-form")?.addEventListener("submit", async event => {
    event.preventDefault();
    const form = event.currentTarget;
    const raw = Object.fromEntries(new FormData(form).entries());
    const payload = {
        sensor_id: raw.sensor_id,
        sentinel_value: Number(raw.sentinel_value),
        reference_value: Number(raw.reference_value),
        reference_instrument: raw.reference_instrument || null,
        technician: raw.technician,
        comment: raw.comment || null,
    };
    try {
        await v6ApiRequest(`/api/equipment/${encodeURIComponent(equipmentId)}/calibrations`, {
            method: "POST",
            body: JSON.stringify(payload),
        });
        window.location.reload();
    } catch (error) {
        window.alert(`Calibration not recorded: ${error.message}`);
    }
});

document.getElementById("refresh-diagnostics")?.addEventListener("click", async buttonEvent => {
    const button = buttonEvent.currentTarget;
    button.disabled = true;
    button.textContent = "Checking…";
    try {
        const result = await v6ApiRequest("/api/system/diagnostics");
        window.alert(`Sentinel diagnostics: ${result.status}\n` + result.checks.map(item => `${item.ok ? "OK" : "FAIL"} · ${item.name}: ${item.detail}`).join("\n"));
    } catch (error) {
        window.alert(`Diagnostics failed: ${error.message}`);
    } finally {
        button.disabled = false;
        button.textContent = "Run diagnostics";
    }
});

document.querySelectorAll("[data-tab-link]").forEach(link => {
    link.addEventListener("click", event => {
        event.preventDefault();
        document.querySelector(`[data-tab="${link.dataset.tabLink}"]`)?.click();
    });
});
