// ============ SUPERADMIN: FORMS ============
// Device provisioning and settings, account editing, per-client schedules.

const { useState: useStateF } = React;

// ---- add a device ----------------------------------------------------------

function DeviceForm({ orgId, units, showToast, onClose, onDone }) {
  // "" means no room. "new" opens the name field. Anything else is a room id.
  // The old version defaulted to the first room and used "" to mean BOTH
  // "none" and "create one", which is how a client ended up with three rooms
  // named after the company.
  const [f, setF] = useStateF({
    name: "", mqttId: "", unitId: units[0] ? units[0].id : "",
    // An IR blaster drives an air conditioner; a sensor measures a room; a
    // meter counts electricity (on JSY clamps or from pulses), water or gas.
    // The clamps and their names are the board's to declare once connected.
    kind: "ir", medium: "electricity", source: "jsy",
  });
  const [newUnit, setNewUnit] = useStateF("");
  const [busy, setBusy] = useStateF(false);

  const submit = async () => {
    if (!f.name.trim() || !f.mqttId.trim()) { showToast("Nom et identifiant MQTT requis"); return; }
    if (f.unitId === "new" && !newUnit.trim()) { showToast("Nommez le nouveau logement"); return; }
    setBusy(true);
    try {
      let unitId = f.unitId === "new" || f.unitId === "" ? null : f.unitId;
      if (f.unitId === "new") {
        const clash = units.find(u => u.name.trim().toLowerCase() === newUnit.trim().toLowerCase());
        if (clash) {
          unitId = clash.id;   // reuse rather than making a second one
        } else {
          const u = await STApi.createUnit(orgId, newUnit.trim());
          unitId = u.id;
        }
      }
      const created = await STApi.createDevice({
        orgId, unitId, name: f.name.trim(), mqttId: f.mqttId.trim(),
        kind: f.kind,
        medium: f.kind === "meter" ? f.medium : null,
        source: f.kind === "meter" ? (f.medium === "electricity" ? f.source : "pulse") : null,
      });
      onDone(created);
    } catch (e) {
      showToast(e.message || "Provisionnement impossible");
    } finally { setBusy(false); }
  };

  return React.createElement(Modal, {
    title: "Ajouter un appareil", sub: "Provisionne l'appareil et génère ses identifiants MQTT",
    onClose,
  },
    React.createElement("div", { className: "modal-body" },
      React.createElement("label", { className: "fld-wrap" },
        React.createElement("span", { className: "fld-label" }, "Type d'appareil"),
        React.createElement("div", { className: "seg" },
          [["ir", "Climatiseur"], ["sensor", "Capteur"], ["meter", "Compteur"]].map(([id, label]) =>
            React.createElement("button", {
              key: id, className: "seg-btn" + (f.kind === id ? " act" : ""),
              onClick: () => setF({ ...f, kind: id }),
            }, label)))),
      f.kind === "meter" && React.createElement(React.Fragment, null,
        React.createElement("label", { className: "fld-wrap" },
          React.createElement("span", { className: "fld-label" }, "Ce que compte l'appareil"),
          React.createElement("div", { className: "seg" },
            [["electricity", "Électricité"], ["water", "Eau"], ["gas", "Gaz"]].map(([id, label]) =>
              React.createElement("button", {
                key: id, className: "seg-btn" + (f.medium === id ? " act" : ""),
                onClick: () => setF({ ...f, medium: id }),
              }, label)))),
        f.medium === "electricity" && React.createElement("label", { className: "fld-wrap" },
          React.createElement("span", { className: "fld-label" }, "Raccordement"),
          React.createElement("div", { className: "seg" },
            [["jsy", "Module JSY (pinces)"], ["pulse", "Sortie impulsions"]].map(([id, label]) =>
              React.createElement("button", {
                key: id, className: "seg-btn" + (f.source === id ? " act" : ""),
                onClick: () => setF({ ...f, source: id }),
              }, label)))),
        React.createElement("p", { className: "fld-help" },
          f.medium === "electricity" && f.source === "jsy"
            ? "Mesure puissance, énergie, tension, courant et fréquence, sur une ou deux pinces."
            : "Ne transmet que ce qu'il compte : l'énergie ou le volume, et un débit moyen.",
          " ", "À sa première connexion, la carte déclare elle-même ses pinces et leurs noms.")),
      React.createElement(Field, {
        label: "Nom affiché", value: f.name, autoFocus: true,
        placeholder: f.kind === "ir" ? "Clim — Salon" : f.kind === "sensor" ? "Capteur — Salon" : "Compteur — Général",
        onChange: e => setF({ ...f, name: e.target.value }),
      }),
      React.createElement(Field, {
        label: "Identifiant MQTT", value: f.mqttId, placeholder: "esp8266-a1b2c3",
        onChange: e => setF({ ...f, mqttId: e.target.value }),
      }),
      React.createElement("p", { className: "fld-help" },
        "Doit être identique à celui affiché sur la page de l'appareil (champ ",
        React.createElement("span", { className: "mono" }, "did"),
        "). Une seule lettre de différence et les messages sont ignorés."),

      React.createElement("label", { className: "fld-wrap" },
        React.createElement("span", { className: "fld-label" }, "Logement"),
        React.createElement("select", {
          className: "fld", value: f.unitId,
          onChange: e => setF({ ...f, unitId: e.target.value }),
        },
          units.map(u => React.createElement("option", { key: u.id, value: u.id }, u.name)),
          React.createElement("option", { value: "" }, "— aucun pour l'instant —"),
          React.createElement("option", { value: "new" }, "+ créer un logement…")
        )
      ),
      f.unitId === "new" && React.createElement(Field, {
        label: "Nom du nouveau logement", value: newUnit, autoFocus: true, placeholder: "Suite 305",
        onChange: e => setNewUnit(e.target.value),
      })
    ),
    React.createElement("div", { className: "modal-foot" },
      React.createElement("button", { className: "btn btn-ghost", onClick: onClose }, "Annuler"),
      React.createElement("button", { className: "btn btn-primary", onClick: submit, disabled: busy },
        busy ? "Provisionnement…" : "Provisionner")
    )
  );
}

// ---- device settings -------------------------------------------------------

function DeviceSettings({ device, units, showToast, onClose, onSaved, onDelete }) {
  const [f, setF] = useStateF({ name: device.name, unitId: device.unit || "" });
  const [busy, setBusy] = useStateF(false);

  // A superadmin loads every room on the platform, so offer only the ones
  // belonging to this device's own client — assigning a device to another
  // company's room would be silently wrong.
  const own = (units || []).filter(u => !device.orgId || !u.orgId || u.orgId === device.orgId);

  const save = async () => {
    setBusy(true);
    try {
      await STApi.updateDevice(device.id, { name: f.name.trim(), unitId: f.unitId || null });
      showToast("Appareil mis à jour");
      onSaved();
    } catch (e) {
      showToast(e.message || "Enregistrement impossible");
    } finally { setBusy(false); }
  };

  return React.createElement(Modal, {
    title: "Paramètres de l'appareil", sub: device.mqtt, onClose,
  },
    React.createElement("div", { className: "modal-body" },
      React.createElement(Field, {
        label: "Nom affiché", value: f.name, autoFocus: true,
        onChange: e => setF({ ...f, name: e.target.value }),
      }),
      React.createElement("label", { className: "fld-wrap" },
        React.createElement("span", { className: "fld-label" }, "Logement (attribution)"),
        React.createElement("select", {
          className: "fld", value: f.unitId,
          onChange: e => setF({ ...f, unitId: e.target.value }),
        },
          React.createElement("option", { value: "" }, "— non affecté —"),
          own.map(u => React.createElement("option", { key: u.id, value: u.id }, u.name))
        )
      ),
      own.length === 0 && React.createElement("p", { className: "fld-help" },
        "Ce client n'a aucun logement. Créez-en un depuis sa fiche, onglet Logements."),

      React.createElement("div", { className: "kv" },
        [["Identifiant MQTT", device.mqtt],
         ["Firmware", device.fw || "—"],
         ["Adresse IP", device.ip || "—"],
         ["Signal", device.signal != null ? device.signal + " dBm" : "—"],
         ["État", device.online ? "En ligne" : "Hors ligne"]].map(([k, v]) =>
          React.createElement("div", { key: k, className: "kv-row" },
            React.createElement("span", { className: "kv-k" }, k),
            React.createElement("span", { className: "kv-v mono" }, v)))
      ),

      React.createElement("div", { className: "note-inline" },
        React.createElement("b", null, "Wi-Fi : "),
        "se règle sur l'appareil lui-même",
        device.ip
          ? React.createElement(React.Fragment, null, " — ",
              React.createElement("a", { href: "http://" + device.ip + "/", target: "_blank", rel: "noreferrer" },
                "ouvrir sa page"))
          : null,
        ". Il n'est pas modifiable d'ici : l'appareil doit déjà être sur le réseau pour recevoir un ordre, ",
        "donc changer son Wi-Fi à distance le déconnecterait sans retour possible."
      )
    ),
    React.createElement("div", { className: "modal-foot" },
      React.createElement("button", { className: "btn btn-danger btn-sm", onClick: onDelete }, "Retirer du parc"),
      React.createElement("div", { style: { flex: 1 } }),
      React.createElement("button", { className: "btn btn-ghost", onClick: onClose }, "Annuler"),
      React.createElement("button", { className: "btn btn-primary", onClick: save, disabled: busy },
        busy ? "Enregistrement…" : "Enregistrer")
    )
  );
}

// ---- account create / edit -------------------------------------------------

function UserForm({ orgId, existing, showToast, onClose, onDone }) {
  const [f, setF] = useStateF({
    name: existing ? existing.name : "",
    email: existing ? existing.email : "",
    role: existing ? existing.role : "team",
  });
  const [busy, setBusy] = useStateF(false);

  const submit = async () => {
    if (!f.name.trim() || !f.email.trim()) { showToast("Nom et e-mail requis"); return; }
    setBusy(true);
    try {
      if (existing) {
        await STApi.updateUser(existing.id, {
          name: f.name.trim(), email: f.email.trim(), role: f.role,
        });
        onDone();
      } else {
        const u = await STApi.createUser({
          name: f.name.trim(), email: f.email.trim(), role: f.role, orgId,
        });
        onDone(u);
      }
    } catch (e) {
      showToast(e.message || "Enregistrement impossible");
    } finally { setBusy(false); }
  };

  return React.createElement(Modal, {
    title: existing ? "Modifier le compte" : "Nouveau compte",
    sub: existing ? existing.email : "Un mot de passe sera généré et affiché une fois",
    onClose,
  },
    React.createElement("div", { className: "modal-body" },
      React.createElement(Field, {
        label: "Nom", value: f.name, autoFocus: true,
        onChange: e => setF({ ...f, name: e.target.value }),
      }),
      React.createElement(Field, {
        label: "E-mail", value: f.email, type: "email",
        onChange: e => setF({ ...f, email: e.target.value }),
      }),
      React.createElement("label", { className: "fld-wrap" },
        React.createElement("span", { className: "fld-label" }, "Rôle"),
        React.createElement("select", {
          className: "fld", value: f.role, onChange: e => setF({ ...f, role: e.target.value }),
        },
          React.createElement("option", { value: "manager" }, "Gestionnaire — contrôle total de sa société"),
          React.createElement("option", { value: "team" }, "Équipe — pilotage des appareils uniquement")
        )
      )
    ),
    React.createElement("div", { className: "modal-foot" },
      React.createElement("button", { className: "btn btn-ghost", onClick: onClose }, "Annuler"),
      React.createElement("button", { className: "btn btn-primary", onClick: submit, disabled: busy },
        busy ? "Enregistrement…" : (existing ? "Enregistrer" : "Créer le compte"))
    )
  );
}

// ---- schedules for this client --------------------------------------------

const BLANK_SCHED = { name: "", time: "14:00", power: "on", target: 22, fan: "auto", unitId: "" };

// cron -> hh:mm and back. Kept next to each other so the two conversions
// cannot drift apart.
function cronToTime(cron) {
  const p = String(cron || "").trim().split(/\s+/);
  return p.length >= 2
    ? `${String(p[1]).padStart(2, "0")}:${String(p[0]).padStart(2, "0")}`
    : "00:00";
}

function schedToForm(s) {
  const a = s.action || {};
  return {
    name: s.name || "",
    time: cronToTime(s.cron),
    power: a.power === false ? "off" : "on",
    target: a.target != null ? a.target : 22,
    fan: a.fan || "auto",
    unitId: (s.unitIds && s.unitIds[0]) || "",
  };
}

function ScheduleTab({ schedules, units, orgId, showToast, reload }) {
  // null = closed, "new" = creating, otherwise the schedule being edited.
  const [editing, setEditing] = useStateF(null);
  const [f, setF] = useStateF(BLANK_SCHED);
  const [busy, setBusy] = useStateF(false);

  const openNew = () => { setF(BLANK_SCHED); setEditing("new"); };
  const openEdit = (s) => { setF(schedToForm(s)); setEditing(s); };

  const save = async () => {
    if (!f.name.trim()) { showToast("Donnez un nom au scénario"); return; }
    const [h, m] = f.time.split(":").map(Number);
    const action = f.power === "off"
      ? { power: false }
      : { power: true, target: Number(f.target), fan: f.fan };
    const body = {
      name: f.name.trim(), cron: `${m} ${h} * * *`, action,
      unitIds: f.unitId ? [f.unitId] : [], days: "Tous les jours",
    };
    setBusy(true);
    try {
      if (editing === "new") {
        await STApi.createSchedule({ orgId, enabled: true, ...body });
        showToast("Scénario créé");
      } else {
        await STApi.updateSchedule(editing.id, body);
        showToast("Scénario modifié");
      }
      setEditing(null);
      setF(BLANK_SCHED);
      reload();
    } catch (e) {
      showToast(e.message || "Enregistrement impossible");
    } finally { setBusy(false); }
  };

  const toggle = async (s) => {
    try { await STApi.updateSchedule(s.id, { enabled: !s.enabled }); reload(); }
    catch (e) { showToast(e.message || "Modification impossible"); }
  };

  const remove = async (s) => {
    if (!confirm(`Supprimer « ${s.name} » ?`)) return;
    try { await STApi.deleteSchedule(s.id); showToast("Scénario supprimé"); reload(); }
    catch (e) { showToast(e.message || "Suppression impossible"); }
  };

  const describe = (a) => {
    if (!a || a.power === false) return "Extinction";
    const bits = ["Allumage"];
    if (a.target != null) bits.push(a.target + " °C");
    if (a.fan) bits.push("ventilation " + a.fan);
    return bits.join(" · ");
  };

  const hhmm = cronToTime;

  return React.createElement(React.Fragment, null,
    React.createElement("div", { className: "head-actions", style: { justifyContent: "flex-end", marginBottom: 12 } },
      React.createElement("button", { className: "btn btn-primary", onClick: openNew },
        React.createElement(Icon, { name: "plus", size: 15 }), "Nouveau scénario")
    ),

    schedules.length === 0
      ? React.createElement("div", { className: "panel empty-panel" },
          "Aucun scénario. Les horaires sont exécutés par le serveur en heure de Casablanca.")
      : React.createElement("div", { className: "panel table-wrap" },
          React.createElement("table", { className: "tbl" },
            React.createElement("thead", null, React.createElement("tr", null,
              ["Scénario", "Heure", "Action", "Portée", "Actif", ""].map((h, i) =>
                React.createElement("th", { key: i, style: i === 4 ? { textAlign: "center" } : {} }, h)))),
            React.createElement("tbody", null,
              schedules.map(s => React.createElement("tr", { key: s.id },
                React.createElement("td", null, s.name),
                React.createElement("td", { className: "mono" }, hhmm(s.cron)),
                React.createElement("td", { className: "td-muted" }, describe(s.action)),
                React.createElement("td", { className: "td-muted" },
                  s.unitIds && s.unitIds.length
                    ? (units.find(u => u.id === s.unitIds[0]) || {}).name || "1 logement"
                    : "Tout le parc"),
                React.createElement("td", { style: { textAlign: "center" } },
                  React.createElement("button", {
                    className: "badge " + (s.enabled ? "badge-ok" : "badge-muted"),
                    style: { cursor: "pointer", border: "none" }, onClick: () => toggle(s),
                  }, s.enabled ? "Actif" : "Suspendu")),
                React.createElement("td", { style: { textAlign: "right", whiteSpace: "nowrap" } },
                  React.createElement("button", { className: "btn btn-ghost btn-sm", onClick: () => openEdit(s) }, "Modifier"),
                  React.createElement("button", { className: "btn btn-ghost btn-sm danger-text", onClick: () => remove(s) }, "Supprimer"))
              )))
          )
        ),

    editing && React.createElement(Modal, {
      title: editing === "new" ? "Nouveau scénario" : "Modifier le scénario",
      sub: "Exécuté chaque jour, en heure de Casablanca",
      onClose: () => setEditing(null),
    },
      React.createElement("div", { className: "modal-body" },
        React.createElement(Field, {
          label: "Nom", value: f.name, autoFocus: true, placeholder: "Pré-climatisation arrivées",
          onChange: e => setF({ ...f, name: e.target.value }),
        }),
        React.createElement("div", { className: "row-2" },
          React.createElement(Field, {
            label: "Heure", type: "time", value: f.time,
            onChange: e => setF({ ...f, time: e.target.value }),
          }),
          React.createElement("label", { className: "fld-wrap" },
            React.createElement("span", { className: "fld-label" }, "Action"),
            React.createElement("select", {
              className: "fld", value: f.power, onChange: e => setF({ ...f, power: e.target.value }),
            },
              React.createElement("option", { value: "on" }, "Allumer"),
              React.createElement("option", { value: "off" }, "Éteindre")
            )
          )
        ),
        f.power === "on" && React.createElement("div", { className: "row-2" },
          React.createElement(Field, {
            label: "Consigne (°C)", type: "number", min: 16, max: 30, value: f.target,
            onChange: e => setF({ ...f, target: e.target.value }),
          }),
          React.createElement("label", { className: "fld-wrap" },
            React.createElement("span", { className: "fld-label" }, "Ventilation"),
            React.createElement("select", {
              className: "fld", value: f.fan, onChange: e => setF({ ...f, fan: e.target.value }),
            },
              ["auto", "low", "med", "high"].map(v =>
                React.createElement("option", { key: v, value: v }, v))
            )
          )
        ),
        React.createElement("label", { className: "fld-wrap" },
          React.createElement("span", { className: "fld-label" }, "Portée"),
          React.createElement("select", {
            className: "fld", value: f.unitId, onChange: e => setF({ ...f, unitId: e.target.value }),
          },
            React.createElement("option", { value: "" }, "Tout le parc du client"),
            units.map(u => React.createElement("option", { key: u.id, value: u.id }, u.name))
          )
        ),
        React.createElement("p", { className: "fld-help" },
          "Les appareils hors ligne sont ignorés. Un ordre à plusieurs champs part en une seule commande ; ",
          "l'appareil enchaîne les touches nécessaires.")
      ),
      React.createElement("div", { className: "modal-foot" },
        React.createElement("button", { className: "btn btn-ghost", onClick: () => setEditing(null) }, "Annuler"),
        React.createElement("button", { className: "btn btn-primary", onClick: save, disabled: busy },
          busy ? "Enregistrement…" : (editing === "new" ? "Créer" : "Enregistrer"))
      )
    )
  );
}

window.DeviceForm = DeviceForm;
window.DeviceSettings = DeviceSettings;
window.UserForm = UserForm;
window.ScheduleTab = ScheduleTab;

// ---- rooms (logements) -----------------------------------------------------
//
// Previously the only way to create one was the inline field in the device
// form, which is how a client ended up with three rooms all named after the
// company. Rooms get their own screen.

function UnitTab({ units, devices, orgId, showToast, reload }) {
  const [adding, setAdding] = useStateF(false);
  const [name, setName] = useStateF("");
  const [editing, setEditing] = useStateF(null);
  const [busy, setBusy] = useStateF(false);

  const countIn = (id) => devices.filter(d => d.unit === id).length;
  const duplicate = (n, exceptId) => units.some(u =>
    u.id !== exceptId && u.name.trim().toLowerCase() === n.trim().toLowerCase());

  const create = async () => {
    const n = name.trim();
    if (!n) { showToast("Donnez un nom au logement"); return; }
    if (duplicate(n) && !confirm(`« ${n} » existe déjà pour ce client. Créer quand même ?`)) return;
    setBusy(true);
    try {
      await STApi.createUnit(orgId, n);
      showToast(`« ${n} » créé`);
      setName(""); setAdding(false); reload();
    } catch (e) { showToast(e.message || "Création impossible"); }
    finally { setBusy(false); }
  };

  const rename = async () => {
    const n = (editing.draft || "").trim();
    if (!n) { showToast("Le nom ne peut pas être vide"); return; }
    setBusy(true);
    try {
      await STApi.renameUnit(orgId, editing.id, n);
      showToast("Logement renommé");
      setEditing(null); reload();
    } catch (e) { showToast(e.message || "Renommage impossible"); }
    finally { setBusy(false); }
  };

  const remove = async (u) => {
    const n = countIn(u.id);
    if (n > 0) {
      showToast(`« ${u.name} » contient ${n} appareil${n > 1 ? "s" : ""} — déplacez-les d'abord`);
      return;
    }
    if (!confirm(`Supprimer le logement « ${u.name} » ?`)) return;
    try { await STApi.deleteUnit(orgId, u.id); showToast("Logement supprimé"); reload(); }
    catch (e) { showToast(e.message || "Suppression impossible"); }
  };

  return React.createElement(React.Fragment, null,
    React.createElement("div", { className: "head-actions", style: { justifyContent: "flex-end", marginBottom: 12 } },
      React.createElement("button", { className: "btn btn-primary", onClick: () => setAdding(true) },
        React.createElement(Icon, { name: "plus", size: 15 }), "Nouveau logement")
    ),

    units.length === 0
      ? React.createElement("div", { className: "panel empty-panel" },
          "Aucun logement. Créez-en un pour y ranger les appareils.")
      : React.createElement("div", { className: "panel table-wrap" },
          React.createElement("table", { className: "tbl" },
            React.createElement("thead", null, React.createElement("tr", null,
              ["Logement", "Appareils", ""].map((h, i) =>
                React.createElement("th", { key: i, style: i === 1 ? { textAlign: "center" } : {} }, h)))),
            React.createElement("tbody", null,
              units.map(u => React.createElement("tr", { key: u.id },
                React.createElement("td", null,
                  React.createElement("div", { className: "td-dev" }, u.name,
                    units.filter(x => x.name.trim().toLowerCase() === u.name.trim().toLowerCase()).length > 1
                      && React.createElement("span", { className: "tag-new", title: "Plusieurs logements portent ce nom" }, "doublon"))),
                React.createElement("td", { style: { textAlign: "center" }, className: "td-muted" }, countIn(u.id)),
                React.createElement("td", { style: { textAlign: "right", whiteSpace: "nowrap" } },
                  React.createElement("button", {
                    className: "btn btn-ghost btn-sm",
                    onClick: () => setEditing({ id: u.id, draft: u.name }),
                  }, "Renommer"),
                  React.createElement("button", {
                    className: "btn btn-ghost btn-sm danger-text", onClick: () => remove(u),
                  }, "Supprimer"))
              )))
          )
        ),

    adding && React.createElement(Modal, {
      title: "Nouveau logement", sub: "Une chambre, un studio, un appartement", onClose: () => setAdding(false),
    },
      React.createElement("div", { className: "modal-body" },
        React.createElement(Field, {
          label: "Nom", value: name, autoFocus: true, placeholder: "Suite 305",
          onChange: e => setName(e.target.value),
          onKeyDown: e => { if (e.key === "Enter") create(); },
        }),
        React.createElement("p", { className: "fld-help" },
          "C'est ce nom que vous choisirez ensuite comme portée d'un scénario de programmation.")
      ),
      React.createElement("div", { className: "modal-foot" },
        React.createElement("button", { className: "btn btn-ghost", onClick: () => setAdding(false) }, "Annuler"),
        React.createElement("button", { className: "btn btn-primary", onClick: create, disabled: busy },
          busy ? "Création…" : "Créer")
      )
    ),

    editing && React.createElement(Modal, {
      title: "Renommer le logement", onClose: () => setEditing(null),
    },
      React.createElement("div", { className: "modal-body" },
        React.createElement(Field, {
          label: "Nom", value: editing.draft, autoFocus: true,
          onChange: e => setEditing({ ...editing, draft: e.target.value }),
          onKeyDown: e => { if (e.key === "Enter") rename(); },
        })
      ),
      React.createElement("div", { className: "modal-foot" },
        React.createElement("button", { className: "btn btn-ghost", onClick: () => setEditing(null) }, "Annuler"),
        React.createElement("button", { className: "btn btn-primary", onClick: rename, disabled: busy },
          busy ? "Enregistrement…" : "Enregistrer")
      )
    )
  );
}

window.UnitTab = UnitTab;
