"use client";

import { useState, useEffect, useCallback } from "react";
import { usePathname, useRouter } from "next/navigation";
import { useClerk, useAuth } from "@clerk/nextjs";
import { X } from "lucide-react";
import { Sidebar } from "@/components/sidebar";
import { TopNav } from "@/components/topnav";
import { AiAvatarButton } from "@/components/ai-avatar-button";
import { AiAvatarPanel } from "@/components/ai-avatar-panel";
import { FeedbackWidget } from "@/components/feedback-widget";
import { BrandProvider, useBrand } from "@/context/brand-context";
import { PlanProvider } from "@/context/plan-context";
import { TaskProvider } from "@/lib/stores/task-store";
import TaskToastContainer from "@/components/ui/task-toast";
import UpgradeModal from "@/components/plan/upgrade-modal";
import { useTrackPageView } from "@/hooks/use-track-page-view";

const AUTH_PAGES = ["/sign-in", "/sign-up"];
// Route prefixes that render outside the authenticated app shell (no
// sidebar / topnav). Matching is exact-segment: `/client` matches the
// client-facing portal at `/client/[brandId]/…` but NOT the agency-side
// `/client-portal-setup` page, which lives on the admin side and needs
// the standard sidebar. Earlier this used pathname.startsWith(p), which
// silently stripped the sidebar from any path that happened to start
// with the prefix string.
const STANDALONE_PREFIXES = ["/admin", "/client", "/portal", "/no-access", "/audit"];
const ONBOARDING_PATH = "/onboarding";
const NO_ACCESS_PATH = "/no-access";

function matchesStandalonePrefix(pathname: string): boolean {
  return STANDALONE_PREFIXES.some((p) => pathname === p || pathname.startsWith(p + "/"));
}

/**
 * Inner shell that manages the AI Avatar state.
 * Lives inside BrandProvider so it can access brand context.
 */
function EarlyAccessBanner() {
  const [dismissed, setDismissed] = useState(true);
  useEffect(() => {
    if (typeof sessionStorage !== "undefined" && !sessionStorage.getItem("meseo_ea_dismissed")) {
      setDismissed(false);
    }
  }, []);
  const dismiss = useCallback(() => {
    setDismissed(true);
    try { sessionStorage.setItem("meseo_ea_dismissed", "1"); } catch {}
  }, []);
  if (dismissed) return null;
  return (
    <div className="bg-slate-900 text-white text-center text-xs py-2 px-4 flex items-center justify-center gap-2 shrink-0">
      <span>You&apos;re using meSEO Early Access. Data accuracy improves as the platform matures.</span>
      <a href="mailto:support@meseoapp.com" className="underline text-slate-300 hover:text-white">Share feedback</a>
      <button onClick={dismiss} className="ml-1 text-slate-500 hover:text-white"><X className="w-3 h-3" /></button>
    </div>
  );
}

const BUILD_SHA = process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA?.slice(0, 7) ?? "dev";

function DemoBanner() {
  const { brand } = useBrand();
  if (!brand.isDemo) return null;
  return (
    <div className="bg-amber-400 text-amber-900 text-center text-xs py-2 px-4 flex items-center justify-center gap-2 shrink-0 font-semibold">
      <span className="inline-block w-2 h-2 rounded-full bg-amber-700 animate-pulse shrink-0" />
      Demo Mode — data is synthetic and for showcase purposes only. No real brand data is shown.
    </div>
  );
}

function AvatarShell({ children }: { children: React.ReactNode }) {
  const [avatarOpen, setAvatarOpen] = useState(false);
  const [sidebarOpen, setSidebarOpen] = useState(false);

  useTrackPageView();

  return (
    <NoBrandAccessGuard>
      <div className="flex h-screen overflow-hidden">
        <Sidebar mobileOpen={sidebarOpen} onMobileClose={() => setSidebarOpen(false)} />
        <div className="flex flex-col flex-1 overflow-hidden min-w-0">
          <EarlyAccessBanner />
          <DemoBanner />
          <TopNav onMenuClick={() => setSidebarOpen(true)} />
          <main className="flex-1 overflow-y-auto p-4 md:p-6">
            {children}
            <footer className="mt-12 pb-4 text-center text-[10px] text-slate-300">
              meSEO Early Access · Build {BUILD_SHA} · <a href="mailto:support@meseoapp.com" className="hover:text-slate-500">support@meseoapp.com</a>
            </footer>
          </main>
        </div>
        <FeedbackWidget />
        <AiAvatarButton onClick={() => setAvatarOpen(true)} />
        <AiAvatarPanel open={avatarOpen} onClose={() => setAvatarOpen(false)} />
      </div>
    </NoBrandAccessGuard>
  );
}

/**
 * Brand-access guard — runs inside BrandProvider so it can read the
 * resolved brands list. When a signed-in user has zero accessible
 * brands (no OrgMembership-as-owner/admin and no BrandMembership
 * grants), redirect to /no-access. Catches:
 *   • brand-new signups
 *   • invited members whose admin hasn't assigned them brands yet
 *   • members who got removed from every brand they had access to
 *
 * Auth-page / standalone-prefix routes are filtered out higher up
 * by the parent shell, so this only fires on the standard app
 * surface where a brand context is required to render anything
 * useful.
 */
function NoBrandAccessGuard({ children }: { children: React.ReactNode }) {
  const router = useRouter();
  const pathname = usePathname();
  const { brands, loading, fetchError } = useBrand();

  useEffect(() => {
    if (loading || fetchError) return;
    if (pathname === NO_ACCESS_PATH) return;
    if (brands.length === 0) {
      router.replace(NO_ACCESS_PATH);
    }
  }, [brands, loading, fetchError, pathname, router]);

  if (!loading && brands.length === 0 && !fetchError && pathname !== NO_ACCESS_PATH) {
    return null;
  }
  return <>{children}</>;
}

/**
 * Beta access gate — checks if user's email is allowed.
 * Shows a clean "Private Beta" page if not.
 */
function BetaGate({ children }: { children: React.ReactNode }) {
  const { signOut } = useClerk();
  const [access, setAccess] = useState<"loading" | "allowed" | "denied">("loading");

  useEffect(() => {
    fetch("/api/auth/check-access")
      .then((r) => r.json())
      .then((d) => setAccess(d.allowed ? "allowed" : "denied"))
      .catch(() => setAccess("allowed")); // fail open if API unreachable
  }, []);

  if (access === "loading") {
    return (
      <div className="min-h-screen flex items-center justify-center bg-slate-50">
        <div className="w-8 h-8 border-4 border-slate-200 border-t-slate-600 rounded-full animate-spin" />
      </div>
    );
  }

  if (access === "denied") {
    return (
      <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100">
        <div className="w-full max-w-sm text-center px-6">
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img src="/images/meseo-logo-white.png" alt="meSEO" className="h-10 w-auto mx-auto mb-6 invert" />
          <div className="bg-white rounded-2xl border border-slate-200 shadow-lg px-8 py-10">
            <div className="w-12 h-12 rounded-full bg-slate-900 flex items-center justify-center mx-auto mb-4">
              <svg className="w-6 h-6 text-white" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <rect width="18" height="11" x="3" y="11" rx="2" ry="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" />
              </svg>
            </div>
            <h1 className="text-xl font-bold text-slate-900 mb-2">Private Beta</h1>
            <p className="text-sm text-slate-500 leading-relaxed mb-6">
              meSEO is currently in private beta. If you believe you should have access, contact{" "}
              <a href="mailto:hello@meseo.io" className="text-brand-600 font-semibold hover:underline">hello@meseo.io</a>
            </p>
            <button
              onClick={() => signOut({ redirectUrl: "/sign-in" })}
              className="w-full px-5 py-2.5 bg-slate-900 text-white text-sm font-semibold rounded-lg hover:bg-slate-800 transition-colors"
            >
              Sign Out
            </button>
          </div>
          <p className="text-[11px] text-slate-400 mt-6">meSEO — Machine Enhanced Search Engine Optimization</p>
        </div>
      </div>
    );
  }

  return <>{children}</>;
}

export function AppShell({ children }: { children: React.ReactNode }) {
  const pathname = usePathname();
  const { isLoaded, isSignedIn } = useAuth();
  const isAuthPage = AUTH_PAGES.some((p) => pathname.startsWith(p));
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
  }, []);

  if (!mounted) return null;

  const isAuditSubdomain =
    window.location.hostname === "audit.meseoapp.com" ||
    window.location.hostname === "audit.localhost";

  if (isAuthPage || pathname === ONBOARDING_PATH || pathname === "/" || matchesStandalonePrefix(pathname) || isAuditSubdomain) {
    return <>{children}</>;
  }

  // Wait for Clerk to resolve before picking a branch. Without this
  // the unauthenticated splash flashes briefly on page refresh for
  // signed-in users (and vice versa), and — the bug we just fixed —
  // both branches were rendering simultaneously, leaving the sign-in
  // splash visible at the bottom of every authenticated page.
  if (!isLoaded) {
    return (
      <div className="min-h-screen flex items-center justify-center bg-slate-50">
        <div className="w-8 h-8 border-4 border-slate-200 border-t-slate-600 rounded-full animate-spin" />
      </div>
    );
  }

  // Signed-in app (with beta gate). BrandProvider + TaskProvider +
  // AvatarShell wrap every authenticated page.
  if (isSignedIn) {
    return (
      <BetaGate>
        <BrandProvider>
          {/* PlanProvider sits inside BrandProvider so useFeatureGate
              always sees the right brandId. The single UpgradeModal
              is rendered once here so any deep component can trigger
              it via usePlanContext().openUpgrade(). */}
          <PlanProvider>
            <TaskProvider>
              <AvatarShell>{children}</AvatarShell>
              <TaskToastContainer />
              <UpgradeModal />
            </TaskProvider>
          </PlanProvider>
        </BrandProvider>
      </BetaGate>
    );
  }

  // Signed-out login prompt — only reached for non-public pages when
  // the user has no session. Clerk middleware usually redirects these
  // to /sign-in, but this is the fallback for any gap.
  return (
    <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100">
      <div className="w-full max-w-md text-center px-6">
        {/* eslint-disable-next-line @next/next/no-img-element */}
        <img src="/meseo-logo-dark.png" alt="meSEO" className="w-40 mx-auto mb-5 object-contain" />

        <h1 className="text-3xl font-bold text-slate-900 mb-2">
          Grow Your Visibility.<br />Prove Your ROI.
        </h1>
        <p className="text-sm text-slate-500 leading-relaxed max-w-xs mx-auto mb-8">
          The all-in-one platform for SEO, LLMO, GEO, AEO, Local SEO, and GBP — built to help agencies and brands measure what matters.
        </p>

        <div className="flex items-center justify-center gap-3 mb-8">
          <a href="/sign-in">
            <button className="px-7 py-3 bg-brand-600 text-white text-sm font-semibold rounded-xl hover:bg-brand-700 transition-colors shadow-sm">
              Sign in
            </button>
          </a>
          <a href="/sign-up">
            <button className="px-7 py-3 bg-white border border-slate-200 text-slate-700 text-sm font-semibold rounded-xl hover:bg-slate-50 transition-colors shadow-sm">
              Create account
            </button>
          </a>
        </div>

        <p className="text-[11px] text-slate-400">Trusted by agencies and multi-location brands.</p>
      </div>
    </div>
  );
}
