// ============================================
// Reliq — Accept workspace invitation
// Public route: /invite
// Handles the workspace invitation email link.
// ============================================

// ── Spinner ───────────────────────────────────────────────────────────────────
const InviteSpinIcon = ({ 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>
);

// ── AcceptInvite component ────────────────────────────────────────────────────
const AcceptInvite = ({ go }) => {
  const API_BASE = (window.reliqAuth && window.reliqAuth.apiBase) || "https://api.reliq.dev";

  // Capture and validate the token from the URL hash at mount time.
  // The hash looks like: #/invite?token=inv_XXXX
  // The URL is cleaned immediately after capture so the token does not
  // remain visible in the address bar or browser history.
  const token = React.useMemo(() => {
    const hash = window.location.hash;
    const logic = window.reliqInviteLogic;
    const raw = logic ? logic.parseInviteToken(hash) : (() => {
      try {
        const qi = hash.indexOf("?");
        if (qi < 0) return "";
        return new URLSearchParams(hash.slice(qi + 1)).get("token") || "";
      } catch (_) { return ""; }
    })();

    if (!raw) return "";

    // Remove token from URL: replaceState does not trigger navigation or a
    // hashchange event, so the component continues with the captured token
    // while the address bar shows only #/invite.
    try {
      window.history.replaceState(null, "", window.location.pathname + "#/invite");
    } catch (_) {}

    return raw;
  }, []);

  // UI phases:
  //   loading        — API call in flight
  //   success        — invite accepted
  //   signup-required — valid token but user not authenticated
  //   wrong-account  — authenticated but email does not match invite
  //   invalid        — token not found, expired, canceled, or already used
  //   error          — unexpected server error
  //   no-token       — no token present in the URL
  const [phase, setPhase] = React.useState(() => token ? "loading" : "no-token");
  const [inviteEmail, setInviteEmail] = React.useState("");
  const [workspaceName, setWorkspaceName] = React.useState("");

  // Submit the token to the backend on mount. Outcome drives the phase transition.
  React.useEffect(() => {
    if (!token || phase !== "loading") return;

    let cancelled = false;

    (async () => {
      try {
        const res = await fetch(API_BASE + "/v1/invites/accept", {
          method: "POST",
          credentials: "include",
          headers: { "Content-Type": "application/json" },
          // Token is never logged — it is only sent to the Reliq API over HTTPS.
          body: JSON.stringify({ token }),
        });

        if (cancelled) return;

        let envelope;
        try { envelope = await res.json(); } catch (_) { envelope = {}; }
        // Backend wraps responses in { data: ..., error: ... }
        const data = envelope.data ?? envelope;

        if (!res.ok) {
          const code = envelope.error?.code || data?.code || "";
          const isAuthed = !!(window.reliqAuth?.isAuthed?.());
          const logic = window.reliqInviteLogic;
          const phase = logic
            ? logic.classifyAcceptError(code, res.status, isAuthed)
            : (res.status === 404 ? (isAuthed ? "wrong-account" : "invalid") : "error");
          setPhase(phase);
          return;
        }

        const logic = window.reliqInviteLogic;
        const outcome = logic ? logic.classifyAcceptResponse(data) : (
          data.accepted === true ? "success" :
          data.signupRequired === true ? "signup-required" : "error"
        );

        if (outcome === "success") {
          // Refresh auth/workspace state to reflect the new membership.
          // This ensures the dashboard and team views show correct permissions
          // without requiring a manual sign-out/sign-in cycle.
          let wsName = "";
          try {
            const me = await window.reliqAuth.fetchMe();
            window.reliqAuth.signIn(me);
            wsName = me?.workspace?.name || "";
          } catch (_) {}
          setWorkspaceName(wsName);
          setPhase("success");
          return;
        }

        if (outcome === "signup-required") {
          setInviteEmail(data.email || "");
          // Preserve token for post-authentication continuation.
          // After sign-in or sign-up, the auth flow reads this pending
          // redirect and returns the user to the invite route, where the
          // token is recaptured and the acceptance is retried with auth cookies.
          // This is the only scenario where the token is stored outside React
          // state, and it mirrors how the existing auth-guard redirect works.
          if (window.reliqAuth?.setPendingRedirect) {
            window.reliqAuth.setPendingRedirect(
              "invite?token=" + encodeURIComponent(token)
            );
          }
          setPhase("signup-required");
          return;
        }

        setPhase("error");
      } catch (_) {
        if (!cancelled) setPhase("error");
      }
    })();

    return () => { cancelled = true; };
  }, [token, phase]); // eslint-disable-line react-hooks/exhaustive-deps

  // ── Shared styles ─────────────────────────────────────────────────────────────
  const containerStyle = { maxWidth:420, margin:"0 auto" };
  const headerStyle = { textAlign:"center", marginBottom:32 };
  const iconBoxStyle = {
    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",
  };
  const h1Style = {
    fontFamily:"var(--font-display)", fontSize:26, fontWeight:600,
    letterSpacing:"-0.02em", margin:"0 0 10px",
  };
  const subtitleStyle = { color:"var(--fg-2)", fontSize:14, lineHeight:1.6, margin:0 };
  const infoBoxStyle = {
    padding:"14px 18px", borderRadius:"var(--r-md)", marginBottom:20,
    background:"var(--bg-2)", border:"1px solid var(--line-2)",
    fontSize:13, lineHeight:1.6,
  };
  const successBoxStyle = {
    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,
  };
  const errorBoxStyle = {
    padding:"14px 18px", borderRadius:"var(--r-md)", marginBottom:20,
    background:"var(--red-bg)", border:"1px solid rgba(239,68,68,0.25)",
    fontSize:13, lineHeight:1.6, color:"var(--red)",
    display:"flex", alignItems:"flex-start", gap:10,
  };
  const linkStyle = { color:"var(--teal)", cursor:"pointer", fontWeight:500 };
  const btnPrimaryStyle = {
    width:"100%", justifyContent:"center", marginTop:4,
  };

  // ── Phase: loading ────────────────────────────────────────────────────────────
  if (phase === "loading") {
    return (
      <LandingLayout go={go} pageTitle="Accepting invitation…">
        <div style={containerStyle}>
          <div style={headerStyle}>
            <div style={{ ...iconBoxStyle, color:"var(--teal)" }}>
              <Icon name="users" size={24} />
            </div>
            <h1 style={h1Style}>Accepting invitation</h1>
            <p style={subtitleStyle}>Verifying your invitation…</p>
          </div>
          <div style={{ display:"flex", justifyContent:"center", paddingTop:8 }}>
            <InviteSpinIcon size={22} />
          </div>
        </div>
      </LandingLayout>
    );
  }

  // ── Phase: success ────────────────────────────────────────────────────────────
  if (phase === "success") {
    const wsLabel = workspaceName || "the workspace";
    return (
      <LandingLayout go={go} pageTitle="You're in">
        <div style={containerStyle}>
          <div style={headerStyle}>
            <div style={{ ...iconBoxStyle, color:"var(--teal)" }}>
              <Icon name="check-circle" size={24} />
            </div>
            <h1 style={h1Style}>You're in.</h1>
            <p style={subtitleStyle}>
              You've joined <strong>{wsLabel}</strong> on Reliq.
            </p>
          </div>

          <div style={successBoxStyle}>
            <Icon name="check" size={16} style={{ color:"var(--teal)", flexShrink:0, marginTop:2 }} />
            <div style={{ fontSize:13 }}>
              Your membership is active. You can now access workspace scans, reports, and settings.
            </div>
          </div>

          <button
            className="btn btn-primary btn-lg"
            style={btnPrimaryStyle}
            onClick={() => go("dashboard")}
          >
            Open workspace <Icon name="arrow-right" size={14} />
          </button>
        </div>
      </LandingLayout>
    );
  }

  // ── Phase: signup-required (not authenticated) ────────────────────────────────
  if (phase === "signup-required") {
    return (
      <LandingLayout go={go} pageTitle="Join workspace">
        <div style={containerStyle}>
          <div style={headerStyle}>
            <div style={{ ...iconBoxStyle, color:"var(--teal)" }}>
              <Icon name="users" size={24} />
            </div>
            <h1 style={h1Style}>You've been invited</h1>
            <p style={subtitleStyle}>
              Sign in or create an account to accept this invitation.
            </p>
          </div>

          {inviteEmail && (
            <div style={infoBoxStyle}>
              <span style={{ color:"var(--fg-3)", fontFamily:"var(--font-mono)", fontSize:10.5, letterSpacing:"0.08em", textTransform:"uppercase" }}>
                Invited email
              </span>
              <div style={{ marginTop:4, fontWeight:500 }}>{inviteEmail}</div>
              <div style={{ marginTop:6, fontSize:12.5, color:"var(--fg-2)" }}>
                Sign in with this email address to accept the invitation.
              </div>
            </div>
          )}

          <button
            className="btn btn-primary btn-lg"
            style={btnPrimaryStyle}
            onClick={() => go("signin")}
          >
            Sign in <Icon name="arrow-right" size={14} />
          </button>

          <div style={{ marginTop:12, textAlign:"center", fontSize:13, color:"var(--fg-2)" }}>
            No account yet?{" "}
            <span style={linkStyle} onClick={() => go("signup")}>
              Create an account
            </span>
          </div>
        </div>
      </LandingLayout>
    );
  }

  // ── Phase: wrong-account ──────────────────────────────────────────────────────
  if (phase === "wrong-account") {
    const handleSignOut = async () => {
      try {
        await window.reliqAuth?.logoutRequest?.();
        window.reliqAuth?.signOut?.();
      } catch (_) {}
      // Clear any stale pending redirect before sending to sign-in
      window.reliqAuth?.clearPendingRedirect?.();
      go("signin");
    };

    return (
      <LandingLayout go={go} pageTitle="Invitation — wrong account">
        <div style={containerStyle}>
          <div style={headerStyle}>
            <div style={{ ...iconBoxStyle, color:"var(--amber, #f59e0b)" }}>
              <Icon name="alert" size={24} />
            </div>
            <h1 style={h1Style}>Wrong account</h1>
            <p style={subtitleStyle}>
              This invitation cannot be accepted with the currently signed-in account.
            </p>
          </div>

          <div style={{ ...infoBoxStyle, marginBottom:16, color:"var(--fg-1)" }}>
            The invitation was sent to a different email address. Sign out and sign in
            with the invited account to accept it.
          </div>

          <button
            className="btn btn-primary btn-lg"
            style={btnPrimaryStyle}
            onClick={handleSignOut}
          >
            Sign out and use another account <Icon name="arrow-right" size={14} />
          </button>

          <div style={{ marginTop:12, textAlign:"center", fontSize:13, color:"var(--fg-2)" }}>
            <span style={linkStyle} onClick={() => go("dashboard")}>← Back to dashboard</span>
          </div>
        </div>
      </LandingLayout>
    );
  }

  // ── Phase: invalid (expired / canceled / used / not found) ───────────────────
  if (phase === "invalid") {
    const isAuthed = !!(window.reliqAuth?.isAuthed?.());
    return (
      <LandingLayout go={go} pageTitle="Invitation not valid">
        <div style={containerStyle}>
          <div style={headerStyle}>
            <div style={{ ...iconBoxStyle, color:"var(--fg-3)" }}>
              <Icon name="x-circle" size={24} />
            </div>
            <h1 style={h1Style}>Invitation not valid</h1>
            <p style={subtitleStyle}>
              This invitation is no longer valid.
            </p>
          </div>

          <div style={{ ...infoBoxStyle, color:"var(--fg-2)", marginBottom:20 }}>
            It may have expired, already been accepted, or been canceled. Ask your
            workspace administrator to send a new invitation.
          </div>

          {isAuthed ? (
            <button
              className="btn btn-primary btn-lg"
              style={btnPrimaryStyle}
              onClick={() => go("dashboard")}
            >
              Go to dashboard <Icon name="arrow-right" size={14} />
            </button>
          ) : (
            <>
              <button
                className="btn btn-primary btn-lg"
                style={btnPrimaryStyle}
                onClick={() => go("signin")}
              >
                Sign in to Reliq <Icon name="arrow-right" size={14} />
              </button>
              <div style={{ marginTop:10, textAlign:"center", fontSize:13, color:"var(--fg-2)" }}>
                <span style={linkStyle} onClick={() => go("")}>← Back to Reliq</span>
              </div>
            </>
          )}
        </div>
      </LandingLayout>
    );
  }

  // ── Phase: no-token ───────────────────────────────────────────────────────────
  if (phase === "no-token") {
    return (
      <LandingLayout go={go} pageTitle="Invalid invitation link">
        <div style={containerStyle}>
          <div style={headerStyle}>
            <div style={{ ...iconBoxStyle, color:"var(--fg-3)" }}>
              <Icon name="link" size={24} />
            </div>
            <h1 style={h1Style}>Invalid invitation link</h1>
            <p style={subtitleStyle}>
              This invitation link is incomplete. Please use the link from your
              invitation email.
            </p>
          </div>
          <div style={{ marginTop:8, textAlign:"center", fontSize:13, color:"var(--fg-2)" }}>
            <span style={linkStyle} onClick={() => go("")}>← Return to Reliq</span>
          </div>
        </div>
      </LandingLayout>
    );
  }

  // ── Phase: error (unexpected) ─────────────────────────────────────────────────
  return (
    <LandingLayout go={go} pageTitle="Invitation error">
      <div style={containerStyle}>
        <div style={headerStyle}>
          <div style={{ ...iconBoxStyle, color:"var(--red)" }}>
            <Icon name="alert" size={24} />
          </div>
          <h1 style={h1Style}>Something went wrong</h1>
          <p style={subtitleStyle}>
            We couldn't process this invitation right now.
          </p>
        </div>

        <div style={{ ...errorBoxStyle, marginBottom:20 }}>
          <Icon name="alert" size={14} style={{ flexShrink:0, marginTop:1 }} />
          <div>
            There was a problem connecting to the server. Please try again or contact
            your workspace administrator.
          </div>
        </div>

        <button
          className="btn btn-primary btn-lg"
          style={btnPrimaryStyle}
          onClick={() => setPhase("loading")}
        >
          Try again
        </button>

        <div style={{ marginTop:12, textAlign:"center", fontSize:13, color:"var(--fg-2)" }}>
          <span style={linkStyle} onClick={() => go("")}>← Return to Reliq</span>
        </div>
      </div>
    </LandingLayout>
  );
};

Object.assign(window, { AcceptInvite });
