"use client";

import { useEffect } from "react";
import { SignIn } from "@clerk/nextjs";
import AuthLayout from "@/components/auth/auth-layout";

const CLERK_APPEARANCE = {
  variables: {
    colorPrimary: "#0F172A",
    colorText: "#1E293B",
    colorBackground: "#FFFFFF",
    borderRadius: "0.5rem",
    fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif",
  },
  elements: {
    formButtonPrimary: "bg-[#0F172A] hover:bg-[#1E293B] shadow-md",
    card: "shadow-none border-0 p-0 w-full",
    headerTitle: "text-xl font-bold",
    headerSubtitle: "text-slate-500",
    socialButtonsBlockButton: "border border-slate-200 hover:bg-slate-50",
    // Mobile keyboard fix: ensure input is visible above the keyboard.
    // touch-manipulation prevents iOS double-tap-to-zoom delay;
    // text-base prevents iOS Safari 16px auto-zoom on focus.
    formFieldInput: "border-slate-300 focus:border-[#0F172A] focus:ring-[#0F172A] w-full text-base touch-manipulation",
    rootBox: "w-full",
    cardBox: "w-full shadow-none",
    header: "hidden",
    footer: "hidden",
    otpCodeFieldInputs: "gap-2",
    // text-base prevents iOS auto-zoom; touch-manipulation for responsiveness
    otpCodeFieldInput: "w-10 h-12 text-base touch-manipulation",
  },
};

export default function SignInPage() {
  useEffect(() => {
    // iOS Safari suppresses the soft keyboard when focus comes from a
    // programmatic .focus() call rather than a user gesture. Clerk's
    // <SignIn /> auto-focuses inputs across multiple internal views
    // (email, then verification code, then any subsequent factor),
    // and the parent component does NOT unmount between view swaps.
    //
    // Prior fix attempts and what was wrong with each:
    //   • 8b2bfd3 — single mount-time blur cascade. Caught the
    //     initial email auto-focus but missed the email→code
    //     transition (no remount means no re-run).
    //   • 22e5ab3 — added a MutationObserver that re-ran the blur
    //     cascade on every DOM mutation. Caught the OTP transition
    //     but ALSO fired during the render cycle that follows the
    //     user's own tap on an OTP box, clobbering the user-gesture
    //     focus before iOS could open the keyboard.
    //
    // This version: track user gestures on the document with capture-
    // phase listeners (so we record intent BEFORE Clerk's own
    // listeners see the event), and only blur when no user gesture
    // happened in the last 350ms. Programmatic auto-focus (Clerk's
    // mount + view-transition focus calls) gets blurred; user-tap
    // focus is left alone so iOS opens the keyboard.
    if (typeof window === "undefined") return;
    if (!window.matchMedia("(hover: none) and (pointer: coarse)").matches) return;

    let lastUserInteractionAt = 0;
    const recordInteraction = () => { lastUserInteractionAt = Date.now(); };

    // touchstart fires before focus, so we know about user intent
    // before any mutation runs. pointerdown covers hybrid touch+pen
    // devices. click is the fallback for accessibility tools that
    // synthesize input. All three at capture phase + passive so we
    // never block scroll or interfere with default behavior.
    document.addEventListener("touchstart", recordInteraction, { capture: true, passive: true });
    document.addEventListener("pointerdown", recordInteraction, { capture: true, passive: true });
    document.addEventListener("click", recordInteraction, { capture: true, passive: true });

    const blurIfProgrammatic = () => {
      const el = document.activeElement;
      if (!el || el === document.body) return;
      if (!("blur" in el)) return;
      // 350ms window: covers iOS focus-after-tap latency (~50–100ms)
      // plus Clerk's render→mutation cascade (~50–200ms) with a
      // safety buffer. Anything beyond that is treated as
      // programmatic and gets blurred.
      if (Date.now() - lastUserInteractionAt < 350) return;
      (el as HTMLElement).blur();
    };

    // Initial blurs to catch Clerk's auto-focus on mount. These
    // fire before any user has had time to tap, so they pass
    // through blurIfProgrammatic's gesture check and clear the
    // auto-focused field.
    const initialTimers = [0, 50, 200, 500].map((d) =>
      window.setTimeout(blurIfProgrammatic, d),
    );

    // Catch view transitions (email → code, factor-one → factor-two,
    // sign-up → verify). Clerk swaps the inner view in place without
    // re-mounting our component, so we observe DOM mutations and
    // re-check after each. blurIfProgrammatic is now safe to call
    // unconditionally — it self-checks user intent.
    const observer = new MutationObserver(() => {
      blurIfProgrammatic();
      window.setTimeout(blurIfProgrammatic, 50);
      window.setTimeout(blurIfProgrammatic, 200);
    });
    observer.observe(document.body, { childList: true, subtree: true });

    // OTP auto-advance fix: Clerk renders 6 separate <input maxLength="1">
    // boxes and calls box[n+1].focus() programmatically after each digit.
    // iOS hides the keyboard on programmatic focus. The 350ms gesture window
    // above can't distinguish this from a user tap — the auto-advance fires
    // within the same tick as the user's keypress, so lastUserInteractionAt
    // is fresh and blurIfProgrammatic skips the blur. Box[n+1] stays focused
    // with the keyboard hidden; subsequent taps on an already-focused box
    // don't fire a new focus event, so the keyboard never reopens.
    //
    // Solution: listen for input events on maxLength=1 inputs (Clerk's OTP
    // boxes). After each digit, schedule a blur of whichever OTHER maxLength=1
    // input Clerk moved focus to. The 20ms delay lets Clerk complete its
    // advance before we check activeElement. After the blur, the user's next
    // tap creates a fresh focus event that iOS recognises as a gesture and
    // re-opens the keyboard.
    const handleOtpDigitInput = (e: Event) => {
      const target = e.target as HTMLInputElement;
      if (target.tagName !== "INPUT" || target.maxLength !== 1) return;
      window.setTimeout(() => {
        const focused = document.activeElement as HTMLInputElement | null;
        if (focused && focused !== target && focused.maxLength === 1) {
          focused.blur();
        }
      }, 20);
    };
    document.addEventListener("input", handleOtpDigitInput, { capture: true });

    return () => {
      document.removeEventListener("touchstart", recordInteraction, { capture: true } as EventListenerOptions);
      document.removeEventListener("pointerdown", recordInteraction, { capture: true } as EventListenerOptions);
      document.removeEventListener("click", recordInteraction, { capture: true } as EventListenerOptions);
      document.removeEventListener("input", handleOtpDigitInput, { capture: true } as EventListenerOptions);
      initialTimers.forEach((t) => window.clearTimeout(t));
      observer.disconnect();
    };
  }, []);

  return (
    <AuthLayout mode="sign-in">
      {/* NO overflow-hidden — it creates a scroll trap on iOS Safari that
          prevents the virtual keyboard from scrolling the focused input
          into view, making it look like the keyboard never appeared. */}
      <div className="w-full max-w-[320px] mx-auto">
        <SignIn
          appearance={CLERK_APPEARANCE}
          forceRedirectUrl="/dashboard"
          signUpUrl="/sign-up"
        />
      </div>
    </AuthLayout>
  );
}
