"use client";

import { useTranslations } from "next-intl";
import { useEffect, useState } from "react";

/**
 * OAuth Callback Page
 *
 * Reads URL params via window.location.search (not useSearchParams) to avoid
 * the Next.js Suspense boundary requirement, which can delay hydration in popup
 * windows that navigate back from a cross-origin OAuth page (e.g. Google).
 * Sends the callback data back via three methods in order of reliability:
 *   1. postMessage to window.opener (may be null after COOP cross-origin nav)
 *   2. BroadcastChannel (same-origin, works across browsing context groups)
 *   3. localStorage storage event (works across browsing context groups)
 */
export default function CallbackPage() {
  const [status, setStatus] = useState<"processing" | "success" | "done" | "manual">("processing");
  const [currentUrl] = useState(() =>
    typeof window === "undefined" ? "" : window.location.href
  );
  const t = useTranslations("auth");

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const code = params.get("code");
    const state = params.get("state");
    const error = params.get("error");
    const errorDescription = params.get("error_description");

    const callbackData = {
      code,
      state,
      error,
      errorDescription,
      fullUrl: window.location.href,
    };

    let sent = false;
    let openerSameOrigin = false;
    const queueStatusUpdate = (nextStatus: "processing" | "success" | "done" | "manual") => {
      queueMicrotask(() => setStatus(nextStatus));
    };

    if (window.opener) {
      try {
        openerSameOrigin = window.opener.location.origin === window.location.origin;
      } catch {
        openerSameOrigin = false;
      }
    }

    // Method 1: postMessage to opener (popup mode).
    // May be null when Google OAuth's COOP header severs the opener reference.
    //
    // Only relay {code, state} to a known-trusted target origin. A wildcard "*"
    // here would leak the OAuth code/state to a hostile opener — e.g. a page
    // that opened this callback URL in a popup to phish the code. The browser
    // delivers postMessage only when the opener's origin matches `targetOrigin`,
    // so iterating over an allowlist lets the same-origin parent and Codex's
    // fixed loopback helper receive it while silently dropping it for any other
    // origin. Methods 2 (BroadcastChannel) and 3 (localStorage) cover the
    // same-origin fallback when the opener was severed by COOP.
    const trustedTargetOrigins = [
      window.location.origin, // Same origin (dashboard popup mode).
      "http://localhost:1455", // Codex helper (fixed loopback port).
      "http://127.0.0.1:1455", // Same Codex helper, IPv4 literal form.
    ];
    if (window.opener) {
      for (const origin of trustedTargetOrigins) {
        try {
          window.opener.postMessage(
            { type: "oauth_callback", data: callbackData },
            origin
          );
          sent = true;
        } catch (e) {
          console.log("postMessage failed:", e);
        }
      }
    }

    // Method 2: BroadcastChannel — works across browsing context groups for same origin.
    try {
      const channel = new BroadcastChannel("oauth_callback");
      channel.postMessage(callbackData);
      channel.close();
      sent = true;
    } catch (e) {
      console.log("BroadcastChannel failed:", e);
    }

    // Method 3: localStorage — triggers storage event in all same-origin windows,
    // regardless of browsing context group isolation from COOP.
    try {
      localStorage.setItem(
        "oauth_callback",
        JSON.stringify({ ...callbackData, timestamp: Date.now() })
      );
      sent = true;
    } catch (e) {
      console.log("localStorage failed:", e);
    }

    if (sent && (code || error)) {
      if (window.opener && openerSameOrigin) {
        queueStatusUpdate("success");
        setTimeout(() => {
          window.close();
          // If close is prevented (browser policy), fall through to manual close prompt.
          setTimeout(() => setStatus("done"), 500);
        }, 1500);
      } else {
        // Opened as a tab, opener severed by COOP, or remote dashboard using a
        // loopback/tunnel callback. Keep the full URL visible as a manual fallback
        // in case the opener cannot receive the cross-origin postMessage.
        queueStatusUpdate("manual");
      }
    } else {
      // No code/error in URL or all send methods failed — show URL for manual copy.
      // Batch the URL and status update so they render together (React 18 auto-batching).
      queueStatusUpdate("manual");
    }
  }, []);

  return (
    <div className="min-h-screen flex items-center justify-center">
      <div className="text-center p-8 max-w-md">
        {status === "processing" && (
          <>
            <div className="size-16 mx-auto mb-4 rounded-full bg-primary/10 flex items-center justify-center">
              <span className="material-symbols-outlined text-3xl text-primary animate-spin">
                progress_activity
              </span>
            </div>
            <h1 className="text-xl font-semibold mb-2">{t("processing")}</h1>
            <p className="text-text-muted">{t("pleaseWait")}</p>
          </>
        )}

        {(status === "success" || status === "done") && (
          <>
            <div className="size-16 mx-auto mb-4 rounded-full bg-green-100 dark:bg-green-900/30 flex items-center justify-center">
              <span className="material-symbols-outlined text-3xl text-green-600">
                check_circle
              </span>
            </div>
            <h1 className="text-xl font-semibold mb-2">{t("authSuccess")}</h1>
            <p className="text-text-muted">
              {status === "success" ? t("windowWillClose") : t("closeTabNow")}
            </p>
          </>
        )}

        {status === "manual" && (
          <>
            <div className="size-16 mx-auto mb-4 rounded-full bg-yellow-100 dark:bg-yellow-900/30 flex items-center justify-center">
              <span className="material-symbols-outlined text-3xl text-yellow-600">info</span>
            </div>
            <h1 className="text-xl font-semibold mb-2">{t("copyUrl")}</h1>
            <p className="text-text-muted mb-4">{t("copyUrlManual")}</p>
            <div className="bg-surface border border-border rounded-lg p-3 text-left">
              <code className="text-xs break-all">{currentUrl}</code>
            </div>
          </>
        )}
      </div>
    </div>
  );
}
