
const t = {
en: {
"common.language":"Language","common.foundation":"Configured","common.brain_live":"Brain available",
"global.fleet":"Fleet","global.alarms":"Alarms","global.trends":"Trends","global.reports":"Reports","global.events":"Events","global.administration":"Administration",
"console.kicker":"Laboratory monitoring","console.assets":"monitored assets","console.online":"Monitoring online","console.online_detail":"Sentinel services available","console.tagline":"Monitoring familiar. Prediction different.",
"summary.assets":"Assets","summary.assets_help":"Registered equipment","summary.healthy":"Healthy","summary.healthy_help":"Health Score ≥ 85","summary.attention":"Attention","summary.attention_help":"Health Score below 85","summary.active_alarms":"Active alarms","summary.active_alarms_help":"Threshold, device, system or predictive",
"alarms.kicker":"Alarm management","alarms.title":"Alarm console","alarms.intro":"One place for active, acknowledged and resolved events, including predictive alarms.","alarms.active":"Active","alarms.ack":"Acknowledged","alarms.resolved":"Resolved",
"alarmcat.threshold":"Threshold","alarmcat.threshold_text":"Temperature or configured limit exceeded.","alarmcat.device":"Device","alarmcat.device_text":"Sensor, logger or communication issue.","alarmcat.system":"System","alarmcat.system_text":"Sentinel platform or infrastructure issue.","alarmcat.predictive":"Predictive","alarmcat.predictive_text":"Degradation detected before a conventional alarm.",
"alarms.list":"Alarm register","alarms.list_title":"Current and recent alarms","alarms.empty_title":"No alarms recorded","alarms.empty_text":"Sentinel will keep this register for active, acknowledged and resolved alarms.","alarms.escalation":"Escalation policy","alarms.escalation_title":"Contact → acknowledgement → escalation","alarms.primary":"Primary contact","alarms.delay":"Acknowledgement delay","alarms.next":"Next contact / group","alarms.audit":"Audit trail","alarms.escalation_text":"The data model is ready for e-mail, SMS, on-call groups, configurable delays and full acknowledgement history.",
"trends.kicker":"Trend explorer","trends.title":"Trends","trends.intro":"Compare temperature and Health Score using real measurement history.","trends.equipment":"Equipment","trends.temperature":"Internal temperature","trends.health":"Health Score","trends.interpretation":"Sentinel interpretation","trends.loading":"Loading real equipment history…","trends.stable":"Recent behavior is stable over the selected measurement window.","trends.health_down":"Health Score has moved down over the selected measurement window.","trends.health_up":"Health Score has improved over the selected measurement window.","trends.no_data":"Not enough history is available for a trend interpretation.",
"reports.kicker":"Reporting","reports.title":"Report center","reports.intro":"Monitoring, alarm, technical and predictive reports are kept separate for clear client use.","reports.monitoring":"Monitoring report","reports.monitoring_text":"Temperature history, availability and measurement continuity.","reports.alarm":"Alarm report","reports.alarm_text":"Alarm lifecycle, acknowledgement and escalation history.","reports.technical":"Technical report","reports.technical_text":"Sentinel Brain findings, root cause and recommended action.","reports.predictive":"Predictive report","reports.predictive_text":"Health Score evolution, degradation signals and prediction horizon.","reports.equipment_reports":"Equipment reports","reports.open_equipment":"Open an equipment to review its current analysis","reports.open":"Open →",
"events.kicker":"Audit trail","events.title":"Events","events.intro":"A chronological log of alarm and administration actions.","events.empty_title":"No events recorded","events.empty_text":"No alarm or administration event has been recorded yet. Sentinel will not create fake audit entries.",
"admin.kicker":"Administration","admin.title":"Sites, equipment and access","admin.intro":"Structure Sentinel like a regulated monitoring platform without hiding the predictive layer.","admin.structure":"Client structure","admin.organization":"Organization","admin.site":"Site","admin.location":"Location","admin.equipment":"Equipment","admin.sensors":"Sensors","admin.roles":"Roles","admin.users":"Users","admin.users_title":"Configured user accounts","admin.auth_pending":"Access configuration","admin.no_users":"No user accounts configured","admin.no_users_text":"Create the first user to configure operational roles and group access.","admin.assets":"Registered equipment","groups.title":"Groups","groups.subtitle":"Laboratory groups and visibility scopes","groups.permission_ready":"Permission scope ready","groups.code":"Code","groups.site":"Site","groups.equipment_count":"Equipment","groups.user_count":"Users","groups.empty_title":"No groups configured","groups.empty_text":"Create groups such as CS4 or CS20, then assign equipment and users to them.","rules.title":"Alarm rules","rules.subtitle":"Rules by site, group or equipment","rules.inheritance":"Inheritance ready","rules.site_scope":"Site rule","rules.group_scope":"Group rule","rules.equipment_scope":"Equipment override","rules.scope":"Scope","rules.empty_title":"No alarm rules configured","rules.empty_text":"The model can store inherited rules at site, group and equipment level.","schedule.title":"Alarm calendar","schedule.subtitle":"Maintenance and suppression windows","schedule.audit":"Auditable suppression","schedule.help":"A schedule never deletes an alarm. It suppresses notifications for a defined scope and period while keeping the reason and audit trail.","schedule.period":"Period","schedule.reason":"Reason","schedule.empty_title":"No suppression window configured","schedule.empty_text":"Future maintenance windows can target a site, a group, one equipment, one alarm category or one alarm code.",
"table.state":"State","table.severity":"Severity","table.category":"Category","table.equipment":"Equipment","table.message":"Message","table.opened":"Opened","table.time":"Time","table.event":"Event","table.actor":"Actor","table.comment":"Comment","table.name":"Name","table.email":"Email","table.role":"Role"
},
fr: {
"common.language":"Langue","common.foundation":"Base prête","common.brain_live":"Brain disponible",
"global.fleet":"Flotte","global.alarms":"Alarmes","global.trends":"Tendances","global.reports":"Rapports","global.events":"Événements","global.administration":"Administration",
"console.kicker":"Monitoring de laboratoire","console.assets":"équipements surveillés","console.online":"Monitoring en ligne","console.online_detail":"Services Sentinel disponibles","console.tagline":"Monitoring familier. Prédiction différente.",
"summary.assets":"Équipements","summary.assets_help":"Équipements enregistrés","summary.healthy":"Sains","summary.healthy_help":"Health Score ≥ 85","summary.attention":"À surveiller","summary.attention_help":"Health Score inférieur à 85","summary.active_alarms":"Alarmes actives","summary.active_alarms_help":"Seuil, équipement, système ou prédictif",
"alarms.kicker":"Gestion des alarmes","alarms.title":"Console alarmes","alarms.intro":"Un seul endroit pour les alarmes actives, acquittées et résolues, y compris prédictives.","alarms.active":"Actives","alarms.ack":"Acquittées","alarms.resolved":"Résolues",
"alarmcat.threshold":"Seuil","alarmcat.threshold_text":"Température ou limite configurée dépassée.","alarmcat.device":"Équipement","alarmcat.device_text":"Problème de sonde, logger ou communication.","alarmcat.system":"Système","alarmcat.system_text":"Problème de plateforme Sentinel ou d’infrastructure.","alarmcat.predictive":"Prédictif","alarmcat.predictive_text":"Dégradation détectée avant une alarme conventionnelle.",
"alarms.list":"Registre des alarmes","alarms.list_title":"Alarmes actuelles et récentes","alarms.empty_title":"Aucune alarme enregistrée","alarms.empty_text":"Sentinel conservera ici les alarmes actives, acquittées et résolues.","alarms.escalation":"Politique d’escalade","alarms.escalation_title":"Contact → acquittement → escalade","alarms.primary":"Contact principal","alarms.delay":"Délai d’acquittement","alarms.next":"Contact / groupe suivant","alarms.audit":"Traçabilité","alarms.escalation_text":"Le modèle de données est prêt pour les e-mails, SMS, groupes d’astreinte, délais configurables et l’historique complet des acquittements.",
"trends.kicker":"Explorateur de tendances","trends.title":"Tendances","trends.intro":"Comparer température et Health Score à partir de l’historique réel des mesures.","trends.equipment":"Équipement","trends.temperature":"Température interne","trends.health":"Health Score","trends.interpretation":"Interprétation Sentinel","trends.loading":"Chargement de l’historique réel…","trends.stable":"Le comportement récent est stable sur la fenêtre de mesures sélectionnée.","trends.health_down":"Le Health Score a diminué sur la fenêtre de mesures sélectionnée.","trends.health_up":"Le Health Score s’est amélioré sur la fenêtre de mesures sélectionnée.","trends.no_data":"L’historique disponible est insuffisant pour interpréter une tendance.",
"reports.kicker":"Rapports","reports.title":"Centre de rapports","reports.intro":"Les rapports de monitoring, alarmes, techniques et prédictifs restent séparés pour une utilisation client claire.","reports.monitoring":"Rapport de monitoring","reports.monitoring_text":"Historique des températures, disponibilité et continuité des mesures.","reports.alarm":"Rapport d’alarmes","reports.alarm_text":"Cycle de vie des alarmes, acquittements et historique d’escalade.","reports.technical":"Rapport technique","reports.technical_text":"Constats du Sentinel Brain, cause probable et action recommandée.","reports.predictive":"Rapport prédictif","reports.predictive_text":"Évolution du Health Score, signaux de dégradation et horizon prédictif.","reports.equipment_reports":"Rapports par équipement","reports.open_equipment":"Ouvrir un équipement pour consulter son analyse actuelle","reports.open":"Ouvrir →",
"events.kicker":"Traçabilité","events.title":"Événements","events.intro":"Journal chronologique des actions d’alarme et des futures modifications d’administration.","events.empty_title":"Journal d’événements prêt","events.empty_text":"Aucun événement d’alarme ou d’administration n’a encore été enregistré. Sentinel ne crée pas de fausses entrées d’audit.",
"admin.kicker":"Administration","admin.title":"Sites, équipements et accès","admin.intro":"Structurer Sentinel comme une plateforme de monitoring réglementée tout en conservant la couche prédictive.","admin.structure":"Structure client","admin.organization":"Organisation","admin.site":"Site","admin.location":"Localisation","admin.equipment":"Équipement","admin.sensors":"Sondes","admin.roles":"Rôles","admin.users":"Utilisateurs","admin.users_title":"Comptes utilisateurs configurés","admin.auth_pending":"Configuration des accès","admin.no_users":"Aucun compte utilisateur configuré","admin.no_users_text":"Créez le premier utilisateur pour configurer les rôles opérationnels et les accès par groupe.","admin.assets":"Équipements enregistrés","groups.title":"Groupes","groups.subtitle":"Groupes laboratoire et périmètres de visibilité","groups.permission_ready":"Périmètre de droits prêt","groups.code":"Code","groups.site":"Site","groups.equipment_count":"Équipements","groups.user_count":"Utilisateurs","groups.empty_title":"Aucun groupe configuré","groups.empty_text":"Crée des groupes comme CS4 ou CS20, puis affecte les équipements et les utilisateurs.","rules.title":"Règles d’alarme","rules.subtitle":"Règles par site, groupe ou équipement","rules.inheritance":"Héritage prêt","rules.site_scope":"Règle site","rules.group_scope":"Règle groupe","rules.equipment_scope":"Exception équipement","rules.scope":"Périmètre","rules.empty_title":"Aucune règle d’alarme configurée","rules.empty_text":"Le modèle peut stocker des règles héritées au niveau site, groupe et équipement.","schedule.title":"Calendrier des alarmes","schedule.subtitle":"Fenêtres de maintenance et d’inhibition","schedule.audit":"Inhibition traçable","schedule.help":"Un calendrier ne supprime jamais une alarme. Il inhibe les notifications pour un périmètre et une période définis tout en conservant la raison et la traçabilité.","schedule.period":"Période","schedule.reason":"Raison","schedule.empty_title":"Aucune fenêtre d’inhibition configurée","schedule.empty_text":"Les futures fenêtres de maintenance pourront cibler un site, un groupe, un équipement, une catégorie d’alarme ou un code d’alarme.",
"table.state":"État","table.severity":"Sévérité","table.category":"Catégorie","table.equipment":"Équipement","table.message":"Message","table.opened":"Début","table.time":"Heure","table.event":"Événement","table.actor":"Utilisateur","table.comment":"Commentaire","table.name":"Nom","table.email":"E-mail","table.role":"Rôle"
}
};

const titles = {
en:{alarms:"Alarm console",trends:"Trends",reports:"Report center",events:"Events",administration:"Administration"},
fr:{alarms:"Console alarmes",trends:"Tendances",reports:"Centre de rapports",events:"Événements",administration:"Administration"}
};

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

function applyLanguage(value){
language=value;
localStorage.setItem("sentinel-language",value);
document.documentElement.lang=value;
document.querySelectorAll("[data-i18n]").forEach(el=>{
const translated=t[value]?.[el.dataset.i18n];
if(translated){el.textContent=translated;}
});
const page=document.body.dataset.page;
const heading=document.getElementById("console-title");
if(heading){heading.textContent=titles[value]?.[page] || "Sentinel";}
document.title=`Sentinel · ${titles[value]?.[page] || "Sentinel"}`;
const selector=document.getElementById("console-language-selector");
if(selector){selector.value=value;}
}

function activateNav(){
const page=document.body.dataset.page;
document.querySelector(`[data-page-link="${page}"]`)?.classList.add("active");
}

function draw(svg,values){
if(!svg || !values.length){return;}
const w=900,h=260,p=22;
const min=Math.min(...values),max=Math.max(...values),span=Math.max(max-min,0.0001);
const points=values.map((v,i)=>{
const x=p+(i/Math.max(values.length-1,1))*(w-2*p);
const y=h-p-((v-min)/span)*(h-2*p);
return `${x.toFixed(1)},${y.toFixed(1)}`;
}).join(" ");
svg.innerHTML=`<line x1="22" y1="238" x2="878" y2="238" class="chart-axis"></line><polyline points="${points}" class="chart-line"></polyline>`;
}

async function loadTrend(){
const selector=document.getElementById("trend-equipment");
if(!selector){return;}
const id=selector.value;
const interpretation=document.getElementById("trend-interpretation-text");
try{
const response=await fetch(`/equipment/${encodeURIComponent(id)}/measurements/history?limit=180`);
if(!response.ok){throw new Error("history unavailable");}
const history=await response.json();
const temperatures=history.map(r=>Number(r.internal_temperature_c)).filter(Number.isFinite);
const scores=history.map(r=>Number(r.health_score)).filter(Number.isFinite);
draw(document.getElementById("temperature-trend-chart"),temperatures);
draw(document.getElementById("health-trend-chart"),scores);
const tv=document.getElementById("trend-temp-value");
const hv=document.getElementById("trend-health-value");
if(tv){tv.textContent=temperatures.length?`${temperatures.at(-1).toFixed(2)} °C`:"—";}
if(hv){hv.textContent=scores.length?`${scores.at(-1).toFixed(0)} / 100`:"—";}
if(interpretation){
let key="trends.no_data";
if(scores.length>=2){
const delta=scores.at(-1)-scores[0];
key=delta<-2?"trends.health_down":delta>2?"trends.health_up":"trends.stable";
}
interpretation.dataset.i18n=key;
interpretation.textContent=t[language][key];
}
}catch(error){
if(interpretation){interpretation.dataset.i18n="trends.no_data";interpretation.textContent=t[language]["trends.no_data"];}
}
}

document.getElementById("console-language-selector")?.addEventListener("change",e=>applyLanguage(e.target.value));
document.getElementById("trend-equipment")?.addEventListener("change",loadTrend);
activateNav();
applyLanguage(language);
loadTrend();


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

function objectFromForm(form) {
    return Object.fromEntries(new FormData(form).entries());
}

function reloadAfter(action) {
    action.then(() => window.location.reload())
        .catch(error => window.alert(error.message));
}

document.getElementById("alarm-group-filter")?.addEventListener("change", event => {
    const value = event.target.value;
    window.location.href = value ? `/alarms?group=${encodeURIComponent(value)}` : "/alarms";
});

document.getElementById("create-user-form")?.addEventListener("submit", event => {
    event.preventDefault();
    const payload = objectFromForm(event.currentTarget);
    reloadAfter(apiRequest("/api/users", {
        method: "POST",
        body: JSON.stringify(payload),
    }));
});

document.querySelectorAll("[data-user-toggle]").forEach(button => {
    button.addEventListener("click", () => {
        const enabled = button.dataset.userEnabled === "1";
        reloadAfter(apiRequest(`/api/users/${button.dataset.userToggle}`, {
            method: "PUT",
            body: JSON.stringify({
                email: button.dataset.userEmail,
                display_name: button.dataset.userName,
                role_code: button.dataset.userRole,
                enabled: !enabled,
            }),
        }));
    });
});

document.querySelectorAll("[data-user-delete]").forEach(button => {
    button.addEventListener("click", () => {
        if (!window.confirm("Delete this user?")) return;
        reloadAfter(apiRequest(`/api/users/${button.dataset.userDelete}`, {
            method: "DELETE",
        }));
    });
});

document.getElementById("create-group-form")?.addEventListener("submit", event => {
    event.preventDefault();
    const payload = objectFromForm(event.currentTarget);
    reloadAfter(apiRequest("/api/groups", {
        method: "POST",
        body: JSON.stringify(payload),
    }));
});

document.querySelectorAll("[data-group-delete]").forEach(button => {
    button.addEventListener("click", () => {
        if (!window.confirm("Delete this group and its assignments?")) return;
        reloadAfter(apiRequest(`/api/groups/${button.dataset.groupDelete}`, {
            method: "DELETE",
        }));
    });
});

document.getElementById("equipment-group-form")?.addEventListener("submit", event => {
    event.preventDefault();
    const payload = objectFromForm(event.currentTarget);
    payload.group_id = Number(payload.group_id);
    reloadAfter(apiRequest("/api/groups/equipment", {
        method: "POST",
        body: JSON.stringify(payload),
    }));
});

document.getElementById("user-group-form")?.addEventListener("submit", event => {
    event.preventDefault();
    const form = event.currentTarget;
    const data = objectFromForm(form);
    const payload = {
        user_id: Number(data.user_id),
        group_id: Number(data.group_id),
        can_view: form.elements.can_view.checked,
        can_acknowledge: form.elements.can_acknowledge.checked,
        can_manage_alarms: form.elements.can_manage_alarms.checked,
    };
    reloadAfter(apiRequest("/api/groups/users", {
        method: "POST",
        body: JSON.stringify(payload),
    }));
});

function syncRuleScope(){
    const type=document.getElementById("rule-scope-type");
    const eq=document.getElementById("rule-target-equipment"), group=document.getElementById("rule-target-group");
    if(!type)return;
    if(eq)eq.hidden=type.value!=="EQUIPMENT";
    if(group)group.hidden=type.value!=="GROUP";
}
function syncRuleMetric(){
    const metric=document.getElementById("rule-metric"), sensorLabel=document.getElementById("rule-sensor-label");
    if(sensorLabel&&metric)sensorLabel.hidden=metric.value==="health_score";
}
document.getElementById("rule-scope-type")?.addEventListener("change",syncRuleScope);
document.getElementById("rule-metric")?.addEventListener("change",syncRuleMetric);
syncRuleScope(); syncRuleMetric();

document.getElementById("create-rule-form")?.addEventListener("submit", event => {
    event.preventDefault();
    const form=event.currentTarget;
    const payload = objectFromForm(form);
    const ruleId=payload.rule_id; delete payload.rule_id;
    if(payload.scope_type==="GROUP") payload.scope_id=document.getElementById("rule-group")?.value || "";
    if(payload.scope_type==="SITE") payload.scope_id="SITE";
    if(payload.metric==="health_score") payload.sensor_id=null;
    payload.threshold = Number(payload.threshold);
    payload.delay_minutes = Number(payload.delay_minutes || 0);
    payload.hysteresis = Number(payload.hysteresis || 0);
    payload.enabled=true;
    reloadAfter(apiRequest(ruleId?`/api/alarm-rules/${ruleId}`:"/api/alarm-rules", {
        method: ruleId?"PUT":"POST",
        body: JSON.stringify(payload),
    }));
});

document.querySelectorAll("[data-rule-edit]").forEach(button=>button.addEventListener("click",()=>{
    const rule=JSON.parse(button.dataset.ruleEdit), form=document.getElementById("create-rule-form"); if(!form)return;
    form.elements.rule_id.value=rule.id; form.elements.name.value=rule.name; form.elements.scope_type.value=rule.scope_type;
    if(rule.scope_type==="EQUIPMENT") form.elements.scope_id.value=rule.scope_id;
    if(rule.scope_type==="GROUP") document.getElementById("rule-group").value=rule.scope_id;
    form.elements.severity.value=rule.severity; form.elements.metric.value=rule.parameters.metric;
    form.elements.operator.value=rule.parameters.operator; form.elements.threshold.value=rule.parameters.threshold;
    form.elements.delay_minutes.value=rule.parameters.delay_minutes||0; form.elements.hysteresis.value=rule.parameters.hysteresis||0;
    document.getElementById("rule-submit").textContent="Save changes"; document.getElementById("rule-cancel-edit").hidden=false;
    syncRuleScope(); syncRuleMetric(); if(rule.scope_type==="EQUIPMENT") loadRuleSensors(rule.parameters.sensor_id); form.scrollIntoView({behavior:"smooth",block:"center"});
}));
document.getElementById("rule-cancel-edit")?.addEventListener("click",()=>location.reload());

document.querySelectorAll("[data-rule-delete]").forEach(button => {
    button.addEventListener("click", () => {
        if (!window.confirm("Delete this alarm rule?")) return;
        reloadAfter(apiRequest(`/api/alarm-rules/${button.dataset.ruleDelete}`, {
            method: "DELETE",
        }));
    });
});

document.getElementById("create-schedule-form")?.addEventListener("submit", event => {
    event.preventDefault();
    syncScheduleTarget();
    const payload = objectFromForm(event.currentTarget);
    const scheduleId = payload.schedule_id; delete payload.schedule_id;
    payload.alarm_category = payload.alarm_category || null; payload.enabled = true;
    reloadAfter(apiRequest(scheduleId ? `/api/alarm-schedules/${scheduleId}` : "/api/alarm-schedules", {
        method: scheduleId ? "PUT" : "POST",
        body: JSON.stringify(payload),
    }));
});

document.querySelectorAll("[data-schedule-toggle]").forEach(button => {
    button.addEventListener("click", () => {
        const enabled = button.dataset.enabled === "1";
        reloadAfter(apiRequest(
            `/api/alarm-schedules/${button.dataset.scheduleToggle}/enabled?enabled=${!enabled}`,
            {method: "PUT"}
        ));
    });
});

document.querySelectorAll("[data-schedule-delete]").forEach(button => {
    button.addEventListener("click", () => {
        if (!window.confirm("Delete this suppression window?")) return;
        reloadAfter(apiRequest(`/api/alarm-schedules/${button.dataset.scheduleDelete}`, {
            method: "DELETE",
        }));
    });
});

document.querySelectorAll("[data-alarm-action]").forEach(button => {
    button.addEventListener("click", () => {
        const action = button.dataset.alarmAction;
        const actor = window.prompt("Your name / initials:");
        if (!actor) return;
        const comment = window.prompt(
            action === "acknowledge"
                ? "Acknowledgement comment:"
                : "Resolution comment:"
        );
        if (!comment) return;

        reloadAfter(apiRequest(
            `/api/alarms/${button.dataset.alarmId}/${action}`,
            {
                method: "POST",
                body: JSON.stringify({actor, comment}),
            }
        ));
    });
});


function showAdminPanel(name) {
    document.querySelectorAll("[data-admin-panel]").forEach(panel => {
        panel.classList.toggle("active", panel.dataset.adminPanel === name);
    });
    document.querySelectorAll("[data-admin-tab]").forEach(tab => {
        tab.classList.toggle("active", tab.dataset.adminTab === name);
    });
    sessionStorage.setItem("sentinel-admin-tab", name);
}

document.querySelectorAll("[data-admin-tab]").forEach(tab => {
    tab.addEventListener("click", () => showAdminPanel(tab.dataset.adminTab));
});

if (document.querySelector("[data-admin-panel]")) {
    showAdminPanel(sessionStorage.getItem("sentinel-admin-tab") || "users");
}

document.querySelectorAll("[data-focus-form]").forEach(button => {
    button.addEventListener("click", () => {
        document.getElementById(button.dataset.focusForm)?.querySelector("input,select")?.focus();
    });
});

async function verifyBackendVersion() {
    const badge = document.getElementById("backend-version-badge");
    const warning = document.getElementById("backend-warning");
    if (!badge) return;

    try {
        const response = await fetch("/api/system/version", {cache: "no-store"});
        if (!response.ok) throw new Error("Old backend");
        const data = await response.json();

        if (data.version !== "7.0.0") {
            badge.textContent = `Backend ${data.version}`;
            badge.classList.add("bad");
            if (warning) warning.hidden = false;
            return;
        }

        badge.textContent = "Backend V7.0 connected";
        badge.classList.add("ok");
        if (warning) warning.hidden = true;
    } catch (_) {
        badge.textContent = "Backend restart required";
        badge.classList.add("bad");
        if (warning) warning.hidden = false;
    }
}

verifyBackendVersion();

async function loadRuleSensors(desired=null){
 const equipment=document.getElementById("rule-equipment");
 const sensor=document.getElementById("rule-sensor");
 const metric=document.getElementById("rule-metric");
 if(!equipment||!sensor)return;
 try{
  const rows=await apiRequest(`/api/equipment/${encodeURIComponent(equipment.value)}/sensors`);
  sensor.innerHTML=rows.map(s=>`<option value="${s.sensor_id}" data-metric="${s.metric}">${s.role} — ${s.sensor_type} — ${s.channel||"—"}</option>`).join("");
  if(desired)sensor.value=desired;
  if(sensor.selectedOptions[0]&&metric){metric.value=sensor.selectedOptions[0].dataset.metric;syncRuleMetric();}
 }catch(e){
  sensor.innerHTML='<option value="">No sensor available</option>';
 }
}
document.getElementById("rule-equipment")?.addEventListener("change",loadRuleSensors);
document.getElementById("rule-sensor")?.addEventListener("change",e=>{const m=document.getElementById("rule-metric"); if(m&&e.target.selectedOptions[0]){m.value=e.target.selectedOptions[0].dataset.metric;syncRuleMetric();}});
loadRuleSensors();
document.getElementById("create-demo-fleet")?.addEventListener("click",async e=>{const b=e.currentTarget;b.disabled=true;b.textContent="Creating demo fleet…";try{const r=await apiRequest("/api/simulation/demo-fleet",{method:"POST"});b.textContent=`${r.simulated_equipment||9} simulated assets created`;setTimeout(()=>location.href="/equipment-overview",700);}catch(err){b.disabled=false;b.textContent="Create / refresh demo fleet";alert(err.message);}});
document.getElementById("clear-demo-fleet")?.addEventListener("click",()=>{if(window.confirm("Remove only the simulated Sentinel demo equipment?"))reloadAfter(apiRequest("/api/simulation/demo-fleet",{method:"DELETE"}));});
const adminHashTabs={"#alarm-rules":"rules","#users":"users","#groups":"groups","#maintenance":"maintenance","#simulation":"simulation","#simulation-lab":"simulation"};
if(adminHashTabs[location.hash]){showAdminPanel(adminHashTabs[location.hash]);}
window.addEventListener("hashchange",()=>{if(adminHashTabs[location.hash])showAdminPanel(adminHashTabs[location.hash]);});


const adminUserSearch=document.getElementById("admin-user-search");
adminUserSearch?.addEventListener("input",()=>{const q=adminUserSearch.value.trim().toLowerCase();document.querySelectorAll(".admin-user-row").forEach(row=>row.style.display=(row.dataset.search||"").toLowerCase().includes(q)?"":"none");});
document.getElementById("alarm-recipient-form")?.addEventListener("submit",event=>{event.preventDefault();const payload=objectFromForm(event.currentTarget);payload.rule_id=Number(payload.rule_id);payload.step_order=Number(payload.step_order);payload.delay_minutes=Number(payload.delay_minutes||0);reloadAfter(apiRequest("/api/alarm-recipients",{method:"POST",body:JSON.stringify(payload)}));});
document.querySelectorAll("[data-recipient-delete]").forEach(button=>button.addEventListener("click",()=>reloadAfter(apiRequest(`/api/alarm-recipients/${button.dataset.recipientDelete}`,{method:"DELETE"}))));
if(location.hash.startsWith("#alarm-")){setTimeout(()=>document.querySelector(location.hash)?.scrollIntoView({behavior:"smooth",block:"center"}),100);}


// V6.4 lifecycle, memberships and maintenance editing
document.querySelectorAll("[data-alarm-details]").forEach(button=>button.addEventListener("click",()=>{
 const row=document.getElementById(`alarm-detail-${button.dataset.alarmDetails}`); if(row) row.hidden=!row.hidden;
}));
document.querySelectorAll("[data-membership-remove-group]").forEach(button=>button.addEventListener("click",()=>{
 if(!confirm(`Remove ${button.dataset.membershipRemoveEquipment} from this group?`))return;
 reloadAfter(apiRequest(`/api/groups/${button.dataset.membershipRemoveGroup}/equipment/${encodeURIComponent(button.dataset.membershipRemoveEquipment)}`,{method:"DELETE"}));
}));
function syncScheduleTarget(){
 const type=document.getElementById("schedule-scope-type"), g=document.getElementById("schedule-target-group"), e=document.getElementById("schedule-target-equipment"), hidden=document.getElementById("schedule-scope-id");
 if(!type||!hidden)return;
 if(g)g.hidden=type.value!=="GROUP"; if(e)e.hidden=type.value!=="EQUIPMENT";
 hidden.value=type.value==="GROUP"?(document.getElementById("schedule-group")?.value||""):type.value==="EQUIPMENT"?(document.getElementById("schedule-equipment")?.value||""):"SITE";
}
document.getElementById("schedule-scope-type")?.addEventListener("change",syncScheduleTarget);
document.getElementById("schedule-group")?.addEventListener("change",syncScheduleTarget);
document.getElementById("schedule-equipment")?.addEventListener("change",syncScheduleTarget); syncScheduleTarget();
document.querySelectorAll("[data-schedule-edit]").forEach(button=>button.addEventListener("click",()=>{
 const item=JSON.parse(button.dataset.scheduleEdit), form=document.getElementById("create-schedule-form"); if(!form)return; showAdminPanel("maintenance");
 form.elements.schedule_id.value=item.id; form.elements.name.value=item.name||""; form.elements.scope_type.value=item.scope_type||"GROUP";
 form.elements.starts_at.value=(item.starts_at||"").slice(0,16); form.elements.ends_at.value=(item.ends_at||"").slice(0,16); form.elements.reason.value=item.reason||""; form.elements.created_by.value=item.created_by||""; form.elements.alarm_category.value=item.alarm_category||"";
 syncScheduleTarget(); if(item.scope_type==="GROUP"&&document.getElementById("schedule-group")){document.getElementById("schedule-group").value=item.scope_id;} if(item.scope_type==="EQUIPMENT"&&document.getElementById("schedule-equipment")){document.getElementById("schedule-equipment").value=item.scope_id;} syncScheduleTarget();
 form.querySelector('button[type="submit"]').textContent="Save changes"; form.scrollIntoView({behavior:"smooth",block:"center"});
}));
