/* global React, GH */
const { useState, useEffect, useRef } = React;

const DEFAULT_REPO = "tamulib-dc-labs/letters-metadata";
const DEFAULT_BRANCH = "main";

// ----- Onboarding overlay (first run) -----
function GHOnboarding({ onDone }) {
  const [step, setStep] = useState("intro"); // intro | pat | oauth | verify
  const [repoInput, setRepoInput] = useState(DEFAULT_REPO);
  const [branch, setBranch] = useState(DEFAULT_BRANCH);
  const [token, setToken] = useState("");
  const [clientId, setClientId] = useState("");
  const [proxyBase, setProxyBase] = useState("");
  const [device, setDevice] = useState(null); // { user_code, verification_uri, ... }
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");
  const pollAbort = useRef(null);

  useEffect(() => () => pollAbort.current?.abort?.(), []);

  const repo = GH.parseRepoUrl(repoInput);

  async function finish(authMode, accessToken) {
    setBusy(true); setErr("");
    try {
      const viewer = await GH.getViewer(accessToken);
      const repoMeta = await GH.getRepoInfo(accessToken, repo);
      const cfg = {
        repo: `${repo.owner}/${repo.repo}`,
        branch: branch || repoMeta.default_branch || "main",
        authMode,
        clientId, proxyBase,
      };
      GH.saveGHConfig(cfg);
      GH.saveGHToken(accessToken);
      GH.saveGHUser({ login: viewer.login, avatar_url: viewer.avatar_url, name: viewer.name });
      onDone({ cfg, token: accessToken, user: viewer });
    } catch (e) {
      setErr(e.message || String(e));
    } finally { setBusy(false); }
  }

  async function startOAuth() {
    setErr(""); setBusy(true);
    try {
      const dev = await GH.deviceFlowStart({ clientId, proxyBase });
      setDevice(dev);
      pollAbort.current = new AbortController();
      const tok = await GH.deviceFlowPoll({
        clientId, proxyBase,
        deviceCode: dev.device_code,
        interval: dev.interval,
        signal: pollAbort.current.signal,
      });
      await finish("oauth", tok);
    } catch (e) {
      setErr(e.message || String(e));
      setBusy(false);
    }
  }

  return (
    <div className="onb-backdrop">
      <div className="onb-card">
        <div className="onb-head">
          <div className="onb-title">Connect to GitHub</div>
          <div className="onb-sub">
            This editor commits your edits as pull requests on a GitHub repo.
            Hosted on GitHub Pages — no server required.
          </div>
        </div>

        {step === "intro" && (
          <div className="onb-body">
            <div className="field">
              <label>Repository</label>
              <input
                type="text"
                value={repoInput}
                onChange={e => setRepoInput(e.target.value)}
                placeholder="owner/repo or https://github.com/owner/repo"
              />
              {!repo && repoInput && (
                <div className="onb-hint warn">Couldn't parse that — use owner/repo or a github.com URL.</div>
              )}
            </div>
            <div className="field">
              <label>Base branch (PRs will target this)</label>
              <input type="text" value={branch} onChange={e => setBranch(e.target.value)} placeholder="main" />
            </div>

            <div className="onb-divider"><span>Sign-in method</span></div>

            <div className="onb-methods">
              <button
                className="onb-method"
                disabled={!repo}
                onClick={() => setStep("oauth")}
              >
                <div className="onb-method-title">Sign in with GitHub <span className="badge">Recommended</span></div>
                <div className="onb-method-sub">
                  Device-flow OAuth. Click, enter a code on github.com, done.
                  Requires a configured OAuth App + CORS proxy.
                </div>
              </button>
              <button
                className="onb-method"
                disabled={!repo}
                onClick={() => setStep("pat")}
              >
                <div className="onb-method-title">Use a Personal Access Token</div>
                <div className="onb-method-sub">
                  Paste a fine-grained PAT with <code>contents:write</code> +
                  <code> pull-requests:write</code> on this repo. Works
                  immediately on GitHub Pages with no extra setup.
                </div>
              </button>
            </div>
          </div>
        )}

        {step === "pat" && (
          <div className="onb-body">
            <div className="field">
              <label>Personal Access Token</label>
              <input
                type="password"
                value={token}
                onChange={e => setToken(e.target.value)}
                placeholder="github_pat_..."
                autoFocus
              />
              <div className="onb-hint">
                Create one at <a href="https://github.com/settings/personal-access-tokens" target="_blank" rel="noreferrer">
                github.com/settings/personal-access-tokens</a>.
                Repository access: <em>Only select repositories</em> →
                <strong> {repo ? `${repo.owner}/${repo.repo}` : "this repo"}</strong>.
                Permissions: <strong>Contents</strong> = Read &amp; write,
                <strong> Pull requests</strong> = Read &amp; write.
              </div>
              <div className="onb-hint warn">
                The token is stored in this browser's localStorage. Don't paste a token from a shared machine.
              </div>
            </div>
            {err && <div className="onb-error">{err}</div>}
            <div className="onb-actions">
              <button onClick={() => { setErr(""); setStep("intro"); }}>Back</button>
              <div style={{ flex: 1 }} />
              <button
                className="primary"
                disabled={!token || !repo || busy}
                onClick={() => finish("pat", token.trim())}
              >
                {busy ? "Verifying…" : "Connect"}
              </button>
            </div>
          </div>
        )}

        {step === "oauth" && (
          <div className="onb-body">
            {!device && (
              <>
                <div className="field">
                  <label>OAuth App Client ID</label>
                  <input
                    type="text"
                    value={clientId}
                    onChange={e => setClientId(e.target.value)}
                    placeholder="Iv1.xxxxxxxxxxxxxxxx"
                  />
                </div>
                <div className="field">
                  <label>CORS proxy base URL</label>
                  <input
                    type="url"
                    value={proxyBase}
                    onChange={e => setProxyBase(e.target.value)}
                    placeholder="https://your-proxy.example.com"
                  />
                  <div className="onb-hint">
                    Browsers can't call GitHub's OAuth token endpoint directly (no CORS).
                    Point this at a tiny proxy that forwards to
                    <code> /login/device/code</code> and
                    <code> /login/oauth/access_token</code>.
                  </div>
                </div>
              </>
            )}
            {device && (
              <div className="onb-device">
                <div className="onb-device-step">
                  1. Open{" "}
                  <a href={device.verification_uri} target="_blank" rel="noreferrer">
                    {device.verification_uri}
                  </a>
                </div>
                <div className="onb-device-step">2. Enter this code:</div>
                <div className="onb-device-code">{device.user_code}</div>
                <div className="onb-device-step muted">Waiting for confirmation…</div>
              </div>
            )}
            {err && <div className="onb-error">{err}</div>}
            <div className="onb-actions">
              <button onClick={() => {
                pollAbort.current?.abort?.();
                setDevice(null); setErr(""); setStep("intro");
              }}>Back</button>
              <div style={{ flex: 1 }} />
              {!device && (
                <button
                  className="primary"
                  disabled={!clientId || !proxyBase || !repo || busy}
                  onClick={startOAuth}
                >
                  {busy ? "Starting…" : "Continue"}
                </button>
              )}
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

// ----- Settings modal (gear icon, after onboarding) -----
function GHSettingsModal({ initial, onClose, onSaved, onDisconnect }) {
  const [repoInput, setRepoInput] = useState(initial?.cfg?.repo || DEFAULT_REPO);
  const [branch, setBranch] = useState(initial?.cfg?.branch || DEFAULT_BRANCH);
  const [token, setToken] = useState("");
  const [showToken, setShowToken] = useState(false);
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");
  const [msg, setMsg] = useState("");

  const repo = GH.parseRepoUrl(repoInput);
  const user = initial?.user;

  async function save() {
    if (!repo) { setErr("Repo must be owner/repo."); return; }
    setBusy(true); setErr(""); setMsg("");
    try {
      const useToken = token || GH.loadGHToken();
      // Verify token still works against this repo
      await GH.getRepoInfo(useToken, repo);
      const cfg = {
        ...initial.cfg,
        repo: `${repo.owner}/${repo.repo}`,
        branch: branch || "main",
      };
      GH.saveGHConfig(cfg);
      if (token) GH.saveGHToken(token.trim());
      onSaved({ cfg, token: useToken });
      setMsg("Saved.");
      setTimeout(() => setMsg(""), 1500);
    } catch (e) {
      setErr(e.message || String(e));
    } finally { setBusy(false); }
  }

  return (
    <div className="onb-backdrop" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="onb-card" style={{ maxWidth: 520 }}>
        <div className="onb-head">
          <div className="onb-title">GitHub settings</div>
          {user && (
            <div className="onb-sub">
              Signed in as{" "}
              <img src={user.avatar_url} alt="" className="onb-avatar" />
              <strong>{user.login}</strong>
              {" "}via {initial?.cfg?.authMode === "oauth" ? "OAuth" : "PAT"}.
            </div>
          )}
        </div>
        <div className="onb-body">
          <div className="field">
            <label>Repository</label>
            <input type="text" value={repoInput} onChange={e => setRepoInput(e.target.value)} />
          </div>
          <div className="field">
            <label>Base branch</label>
            <input type="text" value={branch} onChange={e => setBranch(e.target.value)} />
          </div>
          <div className="field">
            <label>Replace token (optional)</label>
            <div style={{ display: "flex", gap: 6 }}>
              <input
                type={showToken ? "text" : "password"}
                value={token}
                onChange={e => setToken(e.target.value)}
                placeholder="Leave blank to keep the current token"
              />
              <button onClick={() => setShowToken(s => !s)}>{showToken ? "Hide" : "Show"}</button>
            </div>
          </div>
          {err && <div className="onb-error">{err}</div>}
          {msg && <div className="onb-msg">{msg}</div>}
          <div className="onb-actions">
            <button className="danger" onClick={onDisconnect}>Disconnect</button>
            <div style={{ flex: 1 }} />
            <button onClick={onClose}>Close</button>
            <button className="primary" disabled={busy} onClick={save}>
              {busy ? "Saving…" : "Save"}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

window.GHOnboarding = GHOnboarding;
window.GHSettingsModal = GHSettingsModal;
