// ============================================
// Reliq — Sign-in page
// Public route: /signin
// Exports reliqAuth helpers to window for use across all components.
// ============================================

// ── Auth helpers ──────────────────────────────────────────────────────────────
const RELIQ_AUTH_USER         = "reliq_auth_user";
const RELIQ_AUTH_STATUS       = "reliq_auth_status";
// Canonical auth redirect key (Step 3). The auth guard in index.html calls
// reliqAuth.setPendingRedirect() which now writes exclusively to this key.
const RELIQ_AUTH_REDIR        = "reliq_auth_pending_redirect";
// DEPRECATED legacy key — read-only fallback for pre-migration sessions.
// Never write to this constant. Cleared by clearPendingRedirect().
const RELIQ_AUTH_REDIR_LEGACY = "reliq_pending_redirect";

// Production API base. All auth requests validate against the real backend.
const RELIQ_API_BASE = "https://api.reliq.dev";

const reliqAuth = {
  apiBase: RELIQ_API_BASE,

  // ── Real backend auth (production) ────────────────────────────────────────
  // POST /v1/auth/signin — returns the fetch Response so callers inspect res.ok.
  // NEVER sets local authenticated state; that only happens after /v1/auth/me.
  async signInRequest(email, password) {
    return fetch(this.apiBase + "/v1/auth/signin", {
      method: "POST",
      credentials: "include",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email, password }),
    });
  },
  // GET /v1/auth/me — the source of truth for the current session. Throws when
  // the request fails or the session is not authenticated.
  async fetchMe() {
    const res = await fetch(this.apiBase + "/v1/auth/me", {
      method: "GET",
      credentials: "include",
      headers: { "Accept": "application/json" },
    });
    if (!res.ok) {
      const err = new Error("Not authenticated.");
      err.status = res.status;
      throw err;
    }
    const json = await res.json().catch(() => ({}));
    return json.data ?? json;
  },
  // POST /v1/auth/logout — best-effort; local state is cleared regardless.
  async logoutRequest() {
    try {
      await fetch(this.apiBase + "/v1/auth/logout", { method: "POST", credentials: "include" });
    } catch (_) {}
  },

  // ── Local session mirror (stores ONLY real backend user/workspace data) ────
  signIn(user) {
    try {
      localStorage.setItem(RELIQ_AUTH_USER,   JSON.stringify(user));
      localStorage.setItem(RELIQ_AUTH_STATUS,  "authenticated");
    } catch (_) {}
    window.dispatchEvent(new CustomEvent("reliq-auth-change", { detail: user }));
  },
  signOut() {
    try {
      localStorage.removeItem(RELIQ_AUTH_USER);
      localStorage.removeItem(RELIQ_AUTH_STATUS);
    } catch (_) {}
    window.dispatchEvent(new CustomEvent("reliq-auth-change", { detail: null }));
  },
  isAuthed() {
    try {
      return localStorage.getItem(RELIQ_AUTH_STATUS) === "authenticated";
    } catch (_) { return false; }
  },
  getUser() {
    try {
      const raw = localStorage.getItem(RELIQ_AUTH_USER);
      return raw ? JSON.parse(raw) : null;
    } catch (_) { return null; }
  },
  getWorkspace() {
    const session = this.getUser();
    return session?.workspace || null;
  },
  getCurrentWorkspaceId() {
    return this.getWorkspace()?.id || "";
  },
  getMembership() {
    const session = this.getUser();
    return session?.membership || null;
  },
  // Write ONLY to the new canonical key — never to the deprecated legacy key.
  setPendingRedirect(route) {
    try { localStorage.setItem(RELIQ_AUTH_REDIR, route); } catch (_) {}
  },
  // Read new key first; fall back to legacy for sessions predating the Step 3 migration.
  getPendingRedirect() {
    try {
      return localStorage.getItem(RELIQ_AUTH_REDIR)
          || localStorage.getItem(RELIQ_AUTH_REDIR_LEGACY)
          || null;
    } catch (_) { return null; }
  },
  // Clear both the new key and the legacy key — prevents stale redirects from
  // pre-migration sessions from surfacing after auth.
  clearPendingRedirect() {
    try {
      localStorage.removeItem(RELIQ_AUTH_REDIR);
      localStorage.removeItem(RELIQ_AUTH_REDIR_LEGACY);
    } catch (_) {}
  },
};

// Expose immediately so components loaded later (and App) can call it at render time.
Object.assign(window, { reliqAuth });

// ── SpinIcon ──────────────────────────────────────────────────────────────────
const SigninSpinIcon = ({ size = 14 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24"
       style={{ animation:"spin 1s linear infinite", flexShrink:0 }}>
    <circle cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="2.5"
            fill="none" strokeDasharray="40 60" strokeLinecap="round" />
  </svg>
);

// ── Signin component ──────────────────────────────────────────────────────────
const Signin = ({ go }) => {
  // "signin" | "forgot"
  const [mode, setMode] = React.useState("signin");

  // ── Sign-in state ───────────────────────────────────────────────────────────
  const [email,         setEmail]         = React.useState("");
  const [password,      setPassword]      = React.useState("");
  const [fieldErrors,   setFieldErrors]   = React.useState({});
  const [emailLoading,  setEmailLoading]  = React.useState(false);
  const [emailError,    setEmailError]    = React.useState(null);

  const validateSigninField = (field, value) => {
    if (!window.reliqValidate) return null;
    if (field === "email")    return window.reliqValidate.email(value);
    if (field === "password") return value ? null : "Password is required.";
    return null;
  };
  const onBlurSignin = (field, value) => {
    const err = validateSigninField(field, value);
    setFieldErrors(prev => ({ ...prev, [field]: err }));
  };
  const validateSigninAll = () => {
    const errs = {};
    const eErr = validateSigninField("email", email);
    const pErr = validateSigninField("password", password);
    if (eErr) errs.email = eErr;
    if (pErr) errs.password = pErr;
    setFieldErrors(errs);
    return Object.keys(errs).length === 0;
  };

  // ── Forgot-password state ───────────────────────────────────────────────────
  const [resetEmail,    setResetEmail]    = React.useState("");
  const [resetLoading,  setResetLoading]  = React.useState(false);
  const [resetError,    setResetError]    = React.useState(null);
  const [resetSent,     setResetSent]     = React.useState(false);

  // After successful auth: store user, resolve product state, navigate.
  // State-aware routing prevents multi-bounce redirects:
  //   pending_payment → payment (skip dashboard → payment guard bounce)
  //   past_due/canceled → billing (account requires attention)
  //   trialing/active → respect pending redirect, or fall back to dashboard
  const afterAuth = (me) => {
    // Store ONLY the real user/workspace/membership data returned by the backend.
    reliqAuth.signIn(me);

    const sub = window.reliqSubscription;
    const S   = window.RELIQ_USER_STATE;
    if (sub && S) {
      const state = sub.getProductState();
      if (state === S.PENDING_PAYMENT) {
        // Trial signup not yet paid — go straight to payment.
        // Clear any pending redirect (it would just re-bounce via the payment guard).
        reliqAuth.clearPendingRedirect();
        const plan = sub.getSelectedPlan() || "starter";
        go("payment?plan=" + plan + "&trial=7d");
        return;
      }
      if (state === S.PAST_DUE || state === S.CANCELED) {
        // Account issue — send to billing so the user can resolve it.
        reliqAuth.clearPendingRedirect();
        go("billing");
        return;
      }
    }

    // TRIALING, ACTIVE, or reliq-state.jsx unavailable:
    // respect any auth-guard redirect, then fall back to dashboard.
    const dest = reliqAuth.getPendingRedirect() || "dashboard";
    reliqAuth.clearPendingRedirect();
    go(dest);
  };

  // ── Email sign-in (real backend) ──────────────────────────────────────────
  // 1. POST /v1/auth/signin. If not OK → error, no local state, no navigation.
  // 2. GET /v1/auth/me → store the real session, then route into the app.
  const handleEmailSubmit = async (e) => {
    e.preventDefault();
    if (emailLoading) return;
    if (!validateSigninAll()) return;
    setEmailError(null);
    setEmailLoading(true);
    try {
      const res = await reliqAuth.signInRequest(email, password);
      if (!res || !res.ok) {
        setEmailError("Invalid email or password.");
        setEmailLoading(false);
        return;
      }
      // Credentials accepted — fetch the authenticated session before entering.
      const me = await reliqAuth.fetchMe();
      afterAuth(me);
    } catch (err) {
      // Network failure or session fetch failed — do NOT authenticate locally.
      setEmailError(err && err.status === 0
        ? "Couldn’t reach the server. Please try again."
        : "Invalid email or password.");
      setEmailLoading(false);
    }
  };

  // ── Forgot password ─────────────────────────────────────────────────────────
  // Informational only — never authenticates. (Password reset delivery is
  // handled out of band; this does not grant access.)
  const handleReset = async (e) => {
    e.preventDefault();
    if (resetLoading) return;
    setResetError(null);
    if (!resetEmail || !resetEmail.includes("@")) {
      setResetError("Enter a valid email address.");
      return;
    }
    setResetLoading(true);
    setTimeout(() => { setResetSent(true); setResetLoading(false); }, 400);
  };

  const switchToForgot = () => {
    setMode("forgot");
    setResetEmail(email); // pre-fill with whatever the user typed
    setResetError(null);
    setResetSent(false);
  };

  const switchToSignin = () => {
    setMode("signin");
    setEmailError(null);
  };

  // ── Shared styles ───────────────────────────────────────────────────────────
  const fieldStyle  = { display:"flex", flexDirection:"column", gap:6, marginBottom:14 };
  const labelStyle  = {
    fontFamily:"var(--font-mono)", fontSize:10.5,
    letterSpacing:"0.1em", textTransform:"uppercase", color:"var(--fg-3)",
  };
  const inputStyle  = {
    background:"var(--bg-1)", border:"1px solid var(--line-2)",
    borderRadius:"var(--r-sm)", padding:"10px 12px",
    fontSize:13.5, color:"var(--fg-0)", outline:"none",
    width:"100%", transition:"border-color .12s",
    fontFamily:"var(--font-sans)",
  };
  const errorBoxStyle = {
    padding:"9px 14px", borderRadius:8, marginBottom:12,
    background:"var(--red-bg)", border:"1px solid rgba(239,68,68,0.25)",
    color:"var(--red)", fontSize:13,
    display:"flex", alignItems:"center", gap:8,
  };
  const linkStyle = { color:"var(--teal)", cursor:"pointer", fontWeight:500 };

  // ── Forgot-password panel ───────────────────────────────────────────────────
  if (mode === "forgot") {
    return (
      <LandingLayout go={go} pageTitle="Reset password">
        <div style={{ maxWidth:420, margin:"0 auto" }}>

          <div style={{ textAlign:"center", marginBottom:32 }}>
            <div style={{
              width:52, height:52, borderRadius:"var(--r-md)", margin:"0 auto 18px",
              background:"var(--bg-3)", border:"1px solid var(--line-2)",
              display:"grid", placeItems:"center", color:"var(--teal)",
            }}>
              <Icon name="lock" size={24} />
            </div>
            <h1 style={{
              fontFamily:"var(--font-display)", fontSize:26, fontWeight:600,
              letterSpacing:"-0.02em", margin:"0 0 10px",
            }}>
              Reset your password
            </h1>
            <p style={{ color:"var(--fg-2)", fontSize:14, lineHeight:1.6, margin:0 }}>
              Enter your account email and we'll send reset instructions.
            </p>
          </div>

          {resetSent ? (
            <div style={{
              padding:"16px 20px", borderRadius:"var(--r-md)", marginBottom:24,
              background:"var(--teal-bg)", border:"1px solid var(--line-3)",
              display:"flex", alignItems:"flex-start", gap:12,
            }}>
              <Icon name="check-circle" size={16} style={{ color:"var(--teal)", flexShrink:0, marginTop:2 }} />
              <div>
                <div style={{ fontSize:13, fontWeight:500, marginBottom:2 }}>Check your inbox</div>
                <div style={{ fontSize:12.5, color:"var(--fg-2)", lineHeight:1.5 }}>
                  If an account exists for <strong>{resetEmail}</strong>, we'll send reset instructions shortly.
                </div>
              </div>
            </div>
          ) : (
            <form onSubmit={handleReset} noValidate>
              <div style={fieldStyle}>
                <label style={labelStyle}>Email</label>
                <input
                  type="email"
                  placeholder="you@example.com"
                  value={resetEmail}
                  onChange={e => setResetEmail(e.target.value)}
                  disabled={resetLoading}
                  style={{ ...inputStyle, ...(resetLoading ? { opacity:0.6 } : {}) }}
                  onFocus={e => e.target.style.borderColor = "var(--teal)"}
                  onBlur={e  => e.target.style.borderColor = "var(--line-2)"}
                  autoFocus
                />
              </div>

              {resetError && (
                <div style={errorBoxStyle}>
                  <Icon name="alert" size={13} /> {resetError}
                </div>
              )}

              <button
                type="submit"
                className="btn btn-primary btn-lg"
                disabled={resetLoading}
                style={{
                  width:"100%", justifyContent:"center", marginTop:4,
                  opacity: resetLoading ? 0.7 : 1,
                  cursor:  resetLoading ? "not-allowed" : "pointer",
                }}
              >
                {resetLoading
                  ? <><SigninSpinIcon /> Sending…</>
                  : <>Send reset link <Icon name="arrow-right" size={14} /></>
                }
              </button>
            </form>
          )}

          <div style={{ marginTop:20, textAlign:"center", fontSize:13, color:"var(--fg-2)" }}>
            <span style={linkStyle} onClick={switchToSignin}>← Back to sign in</span>
          </div>

        </div>
      </LandingLayout>
    );
  }

  // ── Sign-in panel ───────────────────────────────────────────────────────────
  return (
    <LandingLayout go={go} pageTitle="Sign in">
      <div style={{ maxWidth:420, margin:"0 auto" }}>

        {/* Header */}
        <div style={{ textAlign:"center", marginBottom:32 }}>
          <div style={{
            width:52, height:52, borderRadius:"var(--r-md)", margin:"0 auto 18px",
            background:"var(--bg-3)", border:"1px solid var(--line-2)",
            display:"grid", placeItems:"center", color:"var(--teal)",
          }}>
            <Icon name="shield" size={24} />
          </div>
          <h1 style={{
            fontFamily:"var(--font-display)", fontSize:26, fontWeight:600,
            letterSpacing:"-0.02em", margin:"0 0 10px",
          }}>
            Sign in to Reliq
          </h1>
          <p style={{ color:"var(--fg-2)", fontSize:14, lineHeight:1.6, margin:0 }}>
            Welcome back. Run scans, review reports, and track your fix history.
          </p>
        </div>

        {/* Email form */}
        <form onSubmit={handleEmailSubmit} noValidate>
          <div style={fieldStyle}>
            <label style={labelStyle} htmlFor="si-email">Email</label>
            <input
              id="si-email"
              type="email"
              placeholder="you@example.com"
              value={email}
              onChange={e => { setEmail(e.target.value); if (fieldErrors.email) setFieldErrors(p => ({...p, email:null})); }}
              disabled={emailLoading}
              aria-invalid={!!fieldErrors.email}
              style={{ ...inputStyle, borderColor: fieldErrors.email ? "var(--red)" : undefined, ...(emailLoading ? { opacity:0.6 } : {}) }}
              onFocus={e => { if (!fieldErrors.email) e.target.style.borderColor = "var(--teal)"; }}
              onBlur={e  => { onBlurSignin("email", e.target.value); }}
            />
            {fieldErrors.email && (
              <span style={{fontSize:12, color:"var(--red)", marginTop:2, display:"flex", alignItems:"center", gap:4}}>
                <Icon name="alert" size={11} /> {fieldErrors.email}
              </span>
            )}
          </div>

          <div style={{ ...fieldStyle, marginBottom:6 }}>
            <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between" }}>
              <label style={labelStyle} htmlFor="si-password">Password</label>
              <span
                style={{ ...labelStyle, color:"var(--teal)", cursor:"pointer", letterSpacing:0, textTransform:"none", fontSize:12 }}
                onClick={switchToForgot}
              >
                Forgot password?
              </span>
            </div>
            <input
              id="si-password"
              type="password"
              placeholder="Your password"
              value={password}
              onChange={e => { setPassword(e.target.value); if (fieldErrors.password) setFieldErrors(p => ({...p, password:null})); }}
              disabled={emailLoading}
              aria-invalid={!!fieldErrors.password}
              style={{ ...inputStyle, borderColor: fieldErrors.password ? "var(--red)" : undefined, ...(emailLoading ? { opacity:0.6 } : {}) }}
              onFocus={e => { if (!fieldErrors.password) e.target.style.borderColor = "var(--teal)"; }}
              onBlur={e  => { onBlurSignin("password", e.target.value); }}
            />
            {fieldErrors.password && (
              <span style={{fontSize:12, color:"var(--red)", marginTop:2, display:"flex", alignItems:"center", gap:4}}>
                <Icon name="alert" size={11} /> {fieldErrors.password}
              </span>
            )}
          </div>

          {emailError && (
            <div style={{ ...errorBoxStyle, marginTop:8 }}>
              <Icon name="alert" size={13} /> {emailError}
            </div>
          )}

          <button
            type="submit"
            className="btn btn-primary btn-lg"
            disabled={emailLoading}
            style={{
              width:"100%", justifyContent:"center", marginTop:12,
              opacity: (emailLoading) ? 0.7 : 1,
              cursor:  (emailLoading) ? "not-allowed" : "pointer",
            }}
          >
            {emailLoading
              ? <><SigninSpinIcon /> Signing in…</>
              : <>Sign in <Icon name="arrow-right" size={14} /></>
            }
          </button>
        </form>

        {/* Trust note */}
        <div style={{
          marginTop:20, textAlign:"center",
          fontFamily:"var(--font-mono)", fontSize:12, color:"var(--fg-3)",
        }}>
          No credit card required to start.
        </div>

        {/* Create account link */}
        <div style={{ marginTop:14, textAlign:"center", fontSize:13, color:"var(--fg-2)" }}>
          Don't have an account?{" "}
          <span style={linkStyle} onClick={() => go("/signup")}>
            Create an account
          </span>
        </div>

      </div>
    </LandingLayout>
  );
};

Object.assign(window, { Signin });
