/* Accounts — who signs in under which shared login.
 *
 * Several services give the team one account per handful of designers, and
 * re-deciding who sits where over chat every time is the problem this screen
 * replaces. A tab per service (admins and managers add them), and inside it one
 * block per login with the designers who use it — the People screen's shape,
 * because it is the same question about the same people.
 *
 * Designers read it; admins and managers edit it. The section leads with
 * "Your accounts" so the person who came to look up their own login does not
 * have to scan every block to find their name.
 *
 * There is deliberately no password field: this document is a plain read for
 * every signed-in designer, so putting credentials in it would build a
 * password store nobody asked for. */
(function () {
const { useState, useEffect } = React;

const ACCOUNTS_API = "/api/accounts";
const uid = (p) => p + "_" + Date.now().toString(36) + Math.floor(Math.random() * 1000).toString(36);

/* The split the team already agreed on: every motion designer across the five
   shared logins, mixed by product so one account going down does not stall a
   whole product team. It seeds the screen only while the document has never
   been written — after that the stored document is the truth, and emptying the
   screen deliberately stays empty. Rename the tab or move anyone in the UI. */
const SEED = [
  { label: "Motion team", accounts: [
    { login: "licenses@nove8.com", members: [
      "Galina Miros", "Yana Nazarenko", "Alexey Strechen", "Lyubov Snapkovskaya"] },
    { login: "designteam-1@nove8.com", members: [
      "Stasya Burnashova", "Yefim Myshko", "Kseniia Mamonova", "Maryna Kliuchkivska", "Solomiia Kalichynska"] },
    { login: "designteam-2@nove8.com", members: [
      "Tetiana Khandozhko", "Zlata Korzh", "Tetiana Starchykova", "Andrei Prohorevich"] },
    { login: "designteam-3@nove8.com", members: [
      "Vladislav Lipnitski", "Oksana Kashpruk", "Alesia Boiko", "Mykyta Ivchenko"] },
    { login: "designteam-4@nove8.com", members: [
      "Vladyslav Zernopolskyi", "Vasyl Blazhevych", "Darya Haiduk", "Oleksandr Romaniuha"] },
  ] },
];

/* Members carry the roster's own id where the name matches someone on it, so a
   later rename in People does not orphan them; a name the roster does not know
   still reads, it just keeps a seeded id. */
function seedDoc(roster) {
  const byName = new Map((roster || [])
    .filter((d) => d && d.name)
    .map((d) => [String(d.name).trim().toLowerCase(), d]));
  return {
    services: SEED.map((s, si) => ({
      id: "svc_seed" + si,
      label: s.label,
      accounts: s.accounts.map((a, ai) => ({
        id: "acc_seed" + si + "_" + ai,
        login: a.login,
        note: "",
        members: a.members.map((name) => {
          const d = byName.get(name.trim().toLowerCase());
          return { id: d ? d.id : "seed_" + name.toLowerCase().replace(/[^a-z]+/g, "_"), name };
        }),
      })),
    })),
  };
}

function AccountsTab({ designers, role, meName }) {
  const [doc, setDoc] = useState(null);          // null = still loading
  const [svcId, setSvcId] = useState("");
  const [newSvc, setNewSvc] = useState("");
  const [newLogin, setNewLogin] = useState("");
  const [saving, setSaving] = useState("");
  const canEdit = role === "admin" || role === "manager";

  useEffect(() => {
    let alive = true;
    fetch(ACCOUNTS_API, { cache: "no-store" })
      .then((r) => (r.ok ? r.json() : null))
      .then((j) => {
        if (!alive) return;
        const state = j && j.state;
        if (state && Array.isArray(state.services)) { setDoc(state); return; }
        /* Nothing has ever been written: show the agreed split, and — if this
           person may edit — store it once so everyone else reads the same
           document instead of a copy that only exists in this browser. */
        const seeded = seedDoc(designers);
        setDoc(seeded);
        if (canEdit) {
          fetch(ACCOUNTS_API, {
            method: "PUT",
            headers: { "content-type": "application/json" },
            body: JSON.stringify({ services: seeded.services }),
          }).catch(() => {});
        }
      })
      .catch(() => { if (alive) setDoc({ services: [], offline: true }); });
    return () => { alive = false; };
  }, []);

  const services = (doc && Array.isArray(doc.services)) ? doc.services : [];
  useEffect(() => {
    if (services.length && !services.some((s) => s.id === svcId)) setSvcId(services[0].id);
  }, [services, svcId]);
  const service = services.find((s) => s.id === svcId) || null;

  /* Every edit writes the whole document straight away — it is small, and a
     "Save" button on a page people mostly read would be one more thing to
     forget. The previous state is kept so a failed write can be undone rather
     than leaving the screen disagreeing with the server. */
  const save = (nextServices) => {
    const prev = services;
    setDoc({ ...(doc || {}), services: nextServices });
    setSaving("saving");
    fetch(ACCOUNTS_API, {
      method: "PUT",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ services: nextServices }),
    })
      .then((r) => {
        if (!r.ok) throw new Error("HTTP " + r.status);
        setSaving("saved");
        setTimeout(() => setSaving(""), 1200);
      })
      .catch(() => {
        setDoc({ ...(doc || {}), services: prev });
        setSaving("failed");
      });
  };
  const patchService = (id, patch) =>
    save(services.map((s) => s.id === id ? { ...s, ...patch } : s));
  const patchAccount = (accId, patch) =>
    patchService(svcId, {
      accounts: (service.accounts || []).map((a) => a.id === accId ? { ...a, ...patch } : a)
    });

  const roster = (designers || []).filter((d) => d && d.name);
  const isMe = (m) => !!meName && String(m.name).trim().toLowerCase() === String(meName).trim().toLowerCase();

  /* What the person who opened this page actually came for. */
  const mine = [];
  for (const s of services) {
    for (const a of (s.accounts || [])) {
      if ((a.members || []).some(isMe)) mine.push({ service: s.label, login: a.login, note: a.note });
    }
  }

  if (doc === null) {
    return (
      <div className="acc">
        <div className="acc-toolbar"><h1>Accounts</h1><p>Loading…</p></div>
      </div>
    );
  }

  return (
    <div className="acc">
      <div className="acc-toolbar">
        <h1>Accounts</h1>
        <p>
          Which shared login to sign in with · a tab per service, a block per account
          {canEdit ? " · your edits are saved and visible to everyone" : " · ask an admin or a manager to change anything"}
        </p>
        {saving === "failed" && <span className="acc-save acc-save-bad">Could not save — the change was undone</span>}
        {saving === "saved" && <span className="acc-save">Saved</span>}
        {saving === "saving" && <span className="acc-save">Saving…</span>}
      </div>

      {meName && (
        <div className="acc-mine">
          <span className="acc-mine-label">Your accounts</span>
          {mine.length === 0
            ? <span className="acc-mine-empty">You are not listed on any account yet{canEdit ? "" : " — ask an admin or a manager"}</span>
            : mine.map((m, i) => (
              <span className="acc-mine-chip" key={i}>
                <b>{m.service}</b>
                <span className="acc-mine-login">{m.login}</span>
              </span>
            ))}
        </div>
      )}

      <div className="acc-tabs">
        {services.map((s) => {
          const n = (s.accounts || []).length;
          const mineHere = (s.accounts || []).some((a) => (a.members || []).some(isMe));
          return (
            <button key={s.id} type="button"
              className={"acc-tab" + (s.id === svcId ? " on" : "") + (mineHere ? " acc-tab-mine" : "")}
              title={mineHere ? "You are on an account here" : `${n} account${n === 1 ? "" : "s"}`}
              onClick={() => setSvcId(s.id)}>
              {s.label}
              <span className="acc-tab-n">{n}</span>
            </button>
          );
        })}
        {canEdit && (
          <span className="acc-newtab">
            <input value={newSvc} placeholder="New service…"
              onChange={(e) => setNewSvc(e.target.value)}
              onKeyDown={(e) => {
                if (e.key !== "Enter" || !newSvc.trim()) return;
                const s = { id: uid("svc"), label: newSvc.trim(), accounts: [] };
                save([...services, s]);
                setSvcId(s.id);
                setNewSvc("");
              }} />
          </span>
        )}
        {services.length === 0 && !canEdit && <span className="acc-empty">Nothing here yet</span>}
      </div>

      {service && (
        <>
          {canEdit && (
            <div className="acc-svc-bar">
              <input className="acc-svc-name" value={service.label}
                title="Rename this service"
                onChange={(e) => patchService(service.id, { label: e.target.value })} />
              <input className="acc-login-new" value={newLogin} placeholder="New login, e.g. design5@nove8.com"
                onChange={(e) => setNewLogin(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key !== "Enter" || !newLogin.trim()) return;
                  patchService(service.id, {
                    accounts: [...(service.accounts || []), { id: uid("acc"), login: newLogin.trim(), note: "", members: [] }]
                  });
                  setNewLogin("");
                }} />
              <button className="acc-btn" disabled={!newLogin.trim()}
                onClick={() => {
                  patchService(service.id, {
                    accounts: [...(service.accounts || []), { id: uid("acc"), login: newLogin.trim(), note: "", members: [] }]
                  });
                  setNewLogin("");
                }}>Add account</button>
              <button className="acc-btn acc-btn-ghost acc-del-svc"
                title="Delete this service and its accounts"
                onClick={() => {
                  if (!window.confirm(`Delete "${service.label}" and its ${(service.accounts || []).length} account(s)?`)) return;
                  const next = services.filter((s) => s.id !== service.id);
                  save(next);
                  setSvcId(next[0] ? next[0].id : "");
                }}>Delete service</button>
            </div>
          )}

          <div className="acc-grid">
            {(service.accounts || []).map((a) => {
              const members = a.members || [];
              const taken = new Set(members.map((m) => String(m.name).toLowerCase()));
              const free = roster.filter((d) => !taken.has(String(d.name).toLowerCase()));
              const hasMe = members.some(isMe);
              return (
                <div className={"acc-card" + (hasMe ? " acc-card-mine" : "")} key={a.id}>
                  <div className="acc-card-head">
                    {canEdit
                      ? <input className="acc-login" value={a.login} title="The login designers sign in with"
                          onChange={(e) => patchAccount(a.id, { login: e.target.value })} />
                      : <span className="acc-login acc-login-static">{a.login}</span>}
                    <span className="acc-card-n">{members.length}</span>
                    {canEdit && (
                      <button className="acc-x" title="Delete this account"
                        onClick={() => {
                          if (!window.confirm(`Delete "${a.login}"? Its ${members.length} designer(s) lose this account.`)) return;
                          patchService(service.id, { accounts: (service.accounts || []).filter((x) => x.id !== a.id) });
                        }}>×</button>
                    )}
                  </div>
                  {hasMe && <div className="acc-you">This is your account</div>}
                  {canEdit
                    ? <input className="acc-note" value={a.note || ""} placeholder="Note — e.g. who holds the 2FA"
                        onChange={(e) => patchAccount(a.id, { note: e.target.value })} />
                    : (a.note ? <div className="acc-note acc-note-static">{a.note}</div> : null)}
                  <div className="acc-members">
                    {members.map((m, i) => (
                      <span className={"acc-member" + (isMe(m) ? " acc-member-me" : "")} key={m.id || m.name + i}>
                        {m.name}
                        {isMe(m) && <span className="acc-me-tag">you</span>}
                        {canEdit && (
                          <button title="Remove from this account"
                            onClick={() => patchAccount(a.id, { members: members.filter((x) => x !== m) })}>×</button>
                        )}
                      </span>
                    ))}
                    {members.length === 0 && <span className="acc-empty">Nobody yet</span>}
                  </div>
                  {canEdit && (
                    <select className="acc-add" value=""
                      onChange={(e) => {
                        const d = roster.find((x) => x.id === e.target.value);
                        if (!d) return;
                        patchAccount(a.id, { members: [...members, { id: d.id, name: d.name }] });
                      }}>
                      <option value="">+ Add a designer…</option>
                      {free.map((d) => <option key={d.id} value={d.id}>{d.name}</option>)}
                    </select>
                  )}
                </div>
              );
            })}
            {(service.accounts || []).length === 0 && (
              <span className="acc-empty">
                {canEdit ? "No accounts yet — add the first login above" : "No accounts here yet"}
              </span>
            )}
          </div>

          {/* Nobody should be quietly left without an account: the people this
              service has no login for are named, rather than simply absent. */}
          {canEdit && (() => {
            const placed = new Set();
            for (const a of (service.accounts || [])) for (const m of (a.members || [])) placed.add(String(m.name).toLowerCase());
            const left = roster.filter((d) => !placed.has(String(d.name).toLowerCase()));
            if (!left.length) return null;
            return (
              <div className="acc-left">
                <span className="acc-left-label">Not on any {service.label} account</span>
                {left.map((d) => <span className="acc-left-name" key={d.id}>{d.name}</span>)}
              </div>
            );
          })()}
        </>
      )}
    </div>
  );
}

window.AccountsTab = AccountsTab;
})();
