/* Account page data binder.
 * Replaces the design's demo email/plan/devices with the user's real
 * license state (read from ~/Library/Application Support/Lirelle via
 * Python bridge). Sign out is wired to clear session.json.
 *
 * Manage subscription is intentionally NOT wired yet — we don't have a
 * cabinet URL to open. Will hook to the Lirelle dashboard once it ships.
 */

(function () {
  function esc(s) {
    return String(s == null ? "" : s)
      .replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;").replace(/'/g, "&#39;");
  }

  function initialFor(email) {
    if (!email) return "?";
    var c = email.trim().charAt(0).toUpperCase();
    return c || "?";
  }

  async function loadAccount() {
    var info;
    try {
      info = await window.lumo.call("requestAccountInfo");
    } catch (err) {
      console.error("requestAccountInfo failed:", err);
      return;
    }
    if (!info) return;

    // Header: avatar + email + plan pill.
    // CR (2026-07-01) — respect info.signed_in from the Python side.
    // Before this, sign_out cleared session.json but license.json kept
    // the last-seen email + plan on disk, so the UI kept rendering the
    // logged-in state (avatar, email, "PLUS · UNTIL ..." pill) with no
    // way for the user to see they'd actually been signed out.
    var isSignedIn = (info.signed_in !== false) && !!info.email;
    var head = document.querySelector(".acct-head");
    if (head) {
      if (isSignedIn) {
        head.innerHTML =
          '<div class="acct-avatar">' + esc(initialFor(info.email)) + "</div>"
          + '<div>'
          +   '<div style="font-size:18px;font-weight:600;margin-bottom:6px;">'
          +     esc(info.email)
          +   "</div>"
          +   '<span class="plan-pill">'
          +     '<span class="bdot" style="width:6px;height:6px;border-radius:50%;'
          +       'background:var(--gold,var(--accent,#ebb638));"></span> '
          +     esc(info.plan_label || "Free")
          +     (info.valid_until_human
                ? ' <span style="color:var(--ink-dim);margin-left:8px;">·</span>'
                  + ' <span style="color:var(--ink);">until '
                  + esc(info.valid_until_human) + "</span>"
                : "")
          +   "</span>"
          + "</div>";
      } else {
        head.innerHTML =
          '<div class="acct-avatar" style="opacity:.4">?</div>'
          + '<div>'
          +   '<div style="font-size:18px;font-weight:600;margin-bottom:6px;">'
          +     'Not signed in'
          +   '</div>'
          +   '<div style="font-family:var(--mono);font-size:12px;'
          +     'color:var(--ink,#888f8a);line-height:1.6;">'
          +     'Sign in with your email to sync your subscription + '
          +     'unlock Plus features. Local dictation still works on '
          +     'the Free tier without an account.'
          +   '</div>'
          + '</div>';
      }
    }
    // Rebuild the bottom action row: Sign in when out, Manage/Sign out
    // when in. Preserves the design's button styling.
    var actionRow = document.querySelector(".sec-wrap > div[style*='margin-top: 28px']")
                  || document.querySelector(".sec-wrap > div[style*='margin-top:28px']");
    if (actionRow) {
      if (isSignedIn) {
        actionRow.innerHTML =
          '<button class="btn btn-ghost">Manage subscription</button>'
          + '<button class="btn btn-ghost">'
          +   '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" '
          +     'aria-hidden="true"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 '
          +     '2-2h4M16 17l5-5-5-5M21 12H9" stroke="currentColor" '
          +     'stroke-width="1.7" stroke-linecap="round" stroke-linejoin='
          +     '"round" fill="none"></path></svg> Sign out'
          + '</button>'
          // CR (2026-07-02) — nuclear option: sign out every device on
          // the account. Different button (destructive tint) so a
          // normal Sign Out click doesn't accidentally hit it.
          + '<button class="btn btn-ghost" data-action="sign-out-all" '
          +   'style="color:#e58a8a;border-color:rgba(229,138,138,.28);">'
          +   'Sign out on all devices'
          + '</button>';
        var allBtn = actionRow.querySelector('[data-action="sign-out-all"]');
        if (allBtn) {
          allBtn.addEventListener("click", function () {
            if (!confirm("Sign out on ALL devices? Every Mac signed in "
                         + "under this email will be kicked out next "
                         + "time it contacts the server. Use this if "
                         + "you lost a Mac or think your credentials "
                         + "leaked. You'll need to re-activate with "
                         + "your email on every device you want back."))
              return;
            allBtn.disabled = true;
            allBtn.textContent = "Signing out…";
            window.lumo.call("signOutEverywhere").then(function (res) {
              if (res && res.ok) {
                alert("Signed out on all devices. "
                      + (res.sessions_killed || 0) + " session(s) ended, "
                      + (res.devices_removed || 0) + " device(s) removed.");
                loadAccount();
              } else {
                alert("Couldn't sign out everywhere: "
                      + ((res && res.error) || "unknown"));
                allBtn.disabled = false;
                allBtn.textContent = "Sign out on all devices";
              }
            }).catch(function (err) {
              alert("Sign out threw: " + err);
              allBtn.disabled = false;
              allBtn.textContent = "Sign out on all devices";
            });
          });
        }
      } else {
        actionRow.innerHTML =
          '<button class="btn btn-primary" data-action="sign-in-again">'
          +   'Sign in'
          + '</button>';
        var signInBtn = actionRow.querySelector('[data-action="sign-in-again"]');
        if (signInBtn) {
          signInBtn.addEventListener("click", function () {
            // Send them through the onboarding account page to
            // re-request a magic link, then back to the bank.
            window.lumo.call("openExternalUrl",
              { url: "https://lirelle.us/login" });
          });
        }
      }
    }
    if (!isSignedIn) {
      // Nothing else to paint — clear devices + upgrade banner too.
      var secClear = document.querySelector(".sec-wrap");
      if (secClear) {
        secClear.querySelectorAll(".device-row, [data-upgrade-banner]")
          .forEach(function (n) { n.parentNode.removeChild(n); });
      }
      return;
    }

    // Devices: replace ALL .device-row nodes with the real list from
    // /me (server-side authoritative). Falls back to a single "this Mac"
    // row if the server didn't reply (offline, signed out).
    var sec = document.querySelector(".sec-wrap");
    if (sec) {
      sec.querySelectorAll(".device-row").forEach(function (n) {
        n.parentNode.removeChild(n);
      });
      var lastSecSub = null;
      sec.querySelectorAll(".sec-sub").forEach(function (n) {
        var t = (n.textContent || "").trim().toLowerCase();
        if (t === "devices") lastSecSub = n;
      });

      var devices = Array.isArray(info.devices) ? info.devices.slice() : [];
      var thisId = info.this_machine_id || "";
      // If the server gave us no list (offline / not signed in), fall
      // back to a single synthetic "this Mac" row so the section still
      // renders something useful.
      if (!devices.length) {
        devices = [{
          machine_id: thisId,
          name: info.device_name || "this Mac",
          is_current: true,
          last_seen_human: "active now",
        }];
      } else {
        // Put the current device first so it's the obvious anchor.
        devices.sort(function (a, b) {
          var ac = (a.machine_id === thisId) ? 0 : 1;
          var bc = (b.machine_id === thisId) ? 0 : 1;
          return ac - bc;
        });
      }

      function humanLastSeen(d) {
        if (d.is_current || d.machine_id === thisId) return "active now";
        if (d.last_seen_human) return String(d.last_seen_human);
        if (d.last_seen) {
          try {
            var t = new Date(d.last_seen);
            var diffMs = Date.now() - t.getTime();
            var mins = Math.floor(diffMs / 60000);
            if (mins < 1) return "just now";
            if (mins < 60) return mins + " min ago";
            var hrs = Math.floor(mins / 60);
            if (hrs < 24) return hrs + "h ago";
            var days = Math.floor(hrs / 24);
            if (days < 30) return days + "d ago";
            return t.toISOString().slice(0, 10);
          } catch (e) {
            return String(d.last_seen);
          }
        }
        return "—";
      }

      var insertAfter = lastSecSub;
      devices.forEach(function (d) {
        var row = document.createElement("div");
        row.className = "device-row";
        var isCurrent = (d.is_current === true) || (d.machine_id === thisId);
        var dname = esc(d.machine_name || d.name || d.machine_id || "Unknown Mac");
        var dsub = esc(humanLastSeen(d))
                 + (isCurrent ? " · this device" : "");
        row.innerHTML =
          '<span class="dv-ico">'
          +   '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" '
          +     'aria-hidden="true">'
          +     '<path d="M5 6h14a1 1 0 0 1 1 1v8H4V7a1 1 0 0 1 1-1zM2 18h20" '
          +       'stroke="currentColor" stroke-width="1.7" stroke-linecap="round" '
          +       'stroke-linejoin="round" fill="none"></path></svg>'
          + "</span>"
          + '<div style="flex:1 1 0%;">'
          +   '<div style="font-size:14px;font-weight:500;">' + dname + "</div>"
          +   '<div style="font-family:var(--mono);font-size:11px;'
          +     'color:var(--ink);margin-top:2px;">' + dsub + "</div>"
          + "</div>"
          + (isCurrent
              ? '<span class="badge transcript"><span class="bdot"></span>Current</span>'
              : '<button data-action="remove-device" '
                + 'data-machine-id="' + esc(d.machine_id || "") + '" '
                + 'data-machine-name="' + dname + '" '
                + 'style="appearance:none;-webkit-appearance:none;'
                + 'cursor:pointer;background:transparent;'
                + 'border:1px solid rgba(255,255,255,.12);'
                + 'color:var(--ink,#888f8a);padding:5px 10px;'
                + 'border-radius:6px;font-family:var(--mono);'
                + 'font-size:11px;">Remove</button>');
        // CR (2026-07-02) — Wire Remove click for non-current devices.
        // Confirms with the machine name so a mistap doesn't kick a
        // device off unexpectedly.
        var rmBtn = row.querySelector('[data-action="remove-device"]');
        if (rmBtn) {
          rmBtn.addEventListener("click", function () {
            var mid = rmBtn.dataset.machineId;
            var name = rmBtn.dataset.machineName;
            if (!confirm("Remove \"" + name + "\" from this account? "
                         + "It'll be signed out next time it contacts "
                         + "the server, and won't be able to transcribe "
                         + "or download the cert until you re-activate "
                         + "with your email."))
              return;
            rmBtn.disabled = true;
            rmBtn.textContent = "Removing…";
            window.lumo.call("removeDevice", { machine_id: mid })
              .then(function (res) {
                if (res && res.ok) {
                  loadAccount();
                } else {
                  alert("Couldn't remove: "
                        + ((res && res.error) || "unknown"));
                  rmBtn.disabled = false;
                  rmBtn.textContent = "Remove";
                }
              })
              .catch(function (err) {
                alert("Remove threw: " + err);
                rmBtn.disabled = false;
                rmBtn.textContent = "Remove";
              });
          });
        }
        if (insertAfter && insertAfter.nextSibling) {
          insertAfter.parentNode.insertBefore(row, insertAfter.nextSibling);
          insertAfter = row;
        } else if (insertAfter) {
          insertAfter.parentNode.appendChild(row);
          insertAfter = row;
        } else {
          sec.appendChild(row);
        }
      });
    }

    paintUpgradeBanner(info);
    // CR (2026-07-03) — re-wire Sign out / Manage subscription click
    // handlers. wireSignOut() runs once at init, but loadAccount()
    // rebuilds the action row via innerHTML on every refresh — the
    // old DOM nodes get replaced, so any listener attached at init
    // is lost. Sign out button visibly existed but did nothing after
    // the first re-render, which is what the user reported.
    wireSignOut();
  }

  function wireSignOut() {
    document.querySelectorAll(".btn.btn-ghost").forEach(function (btn) {
      var t = (btn.textContent || "").trim().toLowerCase();
      if (t.indexOf("sign out") >= 0) {
        btn.addEventListener("click", function () {
          if (!confirm("Sign out THIS Mac only? Your other devices stay "
                       + "signed in. Local transcripts + meetings stay on "
                       + "disk. You'll need to re-enter your email + magic "
                       + "link on this Mac to dictate again."))
            return;
          window.lumo.call("signOut").then(function (res) {
            if (res && res.ok) {
              alert("Signed out. Restart Lirelle to use the activation flow.");
              loadAccount();
            } else {
              alert("Sign out failed: " + ((res && res.error) || "unknown"));
            }
          }).catch(function (err) {
            alert("Sign out threw: " + err);
          });
        });
      }
      // CR (2026-06-27) — Manage subscription now opens the cabinet
      // (lirelle.us/cabinet) in the default browser. Cabinet redirects
      // unauthenticated visitors to /login, which emails a magic-link.
      // After click the user lands back in /cabinet with their plan +
      // invoice history + upgrade buttons.
      if (t.indexOf("manage subscription") >= 0) {
        btn.addEventListener("click", function () {
          window.lumo.call("openExternalUrl",
            { url: "https://lirelle.us/cabinet" })
            .then(function (res) {
              if (!res || !res.ok) {
                alert("Couldn't open cabinet: "
                      + ((res && res.error) || "unknown"));
              }
            });
        });
      }
    });
    // Upgrade button — only when the user is on Free.
    document.querySelectorAll('[data-action="upgrade"]').forEach(function (btn) {
      btn.addEventListener("click", function () {
        window.lumo.call("openExternalUrl",
          { url: "https://lirelle.us/cabinet" });
      });
    });
  }

  // CR (2026-06-27) — when the user is on Free, surface a prominent
  // Upgrade CTA above Devices so they have a discoverable way to pay
  // without leaving the app. Paid users see the existing Manage
  // subscription button only.
  function paintUpgradeBanner(info) {
    var sec = document.querySelector(".sec-wrap");
    if (!sec) return;
    var existing = sec.querySelector('[data-upgrade-banner="1"]');
    var plan = String(info.plan || "free").toLowerCase();
    if (plan !== "free") {
      if (existing) existing.parentNode.removeChild(existing);
      return;
    }
    if (existing) return;
    var head = sec.querySelector(".acct-head");
    var banner = document.createElement("div");
    banner.dataset.upgradeBanner = "1";
    banner.style.cssText =
      "margin-top:20px;padding:18px 20px;border-radius:14px;"
      + "background:linear-gradient(135deg,rgba(235,182,56,.14),"
      + "rgba(235,182,56,.04));border:1px solid rgba(235,182,56,.28);"
      + "display:flex;align-items:center;justify-content:space-between;gap:18px;";
    banner.innerHTML =
      '<div style="flex:1 1 0%;">'
      +   '<div style="font-family:var(--display);font-size:16px;'
      +     'color:var(--text,#efeae4);margin-bottom:4px;">'
      +     'Upgrade to unlock meetings + polished cleanup'
      +   '</div>'
      +   '<div style="font-family:var(--mono);font-size:11.5px;'
      +     'color:var(--ink,#888f8a);line-height:1.5;">'
      +     'Lite 299₽/mo or 2390₽/yr · Plus 899₽/mo or 7190₽/yr · '
      +     'opens in your browser, returns to the app after payment.'
      +   '</div>'
      + '</div>'
      + '<button data-action="upgrade" '
      +   'style="appearance:none;-webkit-appearance:none;cursor:pointer;'
      +   'background:var(--accent,#ebb638);color:#050505;border:none;'
      +   'padding:10px 18px;border-radius:10px;font-family:var(--mono);'
      +   'font-size:12px;font-weight:600;white-space:nowrap;">'
      +   'Upgrade →'
      + '</button>';
    if (head && head.nextSibling) {
      head.parentNode.insertBefore(banner, head.nextSibling);
    } else {
      sec.appendChild(banner);
    }
    banner.querySelector('[data-action="upgrade"]')
      .addEventListener("click", function () {
        window.lumo.call("openExternalUrl",
          { url: "https://lirelle.us/cabinet" });
      });
  }

  function init() {
    wireSignOut();
    loadAccount();
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();
