"use client";

import * as React from "react";
import { useRouter } from "next/navigation";

export interface AdminAuthUser {
  id: string;
  email: string;
  name: string;
  level: "MAIN_ADMIN" | "SUB_ADMIN";
  role: string;
  status: string;
  twoFactorEnabled: boolean;
  hasPasskey: boolean;
  passkeyCount: number;
  hasPin: boolean;
  displayName?: string;
  jobTitle?: string;
  avatarUrl?: string | null;
  avatarMediaId?: string | null;
  socials?: Record<string, string>;
  createdAt?: string;
  lastLoginAt?: string | null;
}

export interface AdminAuthSession {
  id: string;
  device?: string | null;
  browser?: string | null;
  createdAt: string;
  lastActiveAt?: string;
  isLocked: boolean;
  lockedAt?: string | null;
}

export interface AdminAuthContextType {
  user: AdminAuthUser;
  session: AdminAuthSession;
  permissions: string[];
  pendingResetRequestsCount: number;
  isLocked: boolean;
  setIsLocked: (val: boolean) => void;
  refreshAuth: () => Promise<void>;
  logout: () => Promise<void>;
  isAuthenticated: boolean;
  isLoading: boolean;
  hasPasskey: boolean;
  passkeyCount: number;
  hasPin: boolean;
}

const DEFAULT_AUTH_CONTEXT: AdminAuthContextType = {
  user: {
    id: "",
    email: "",
    name: "",
    level: "SUB_ADMIN",
    role: "ADMIN",
    status: "ACTIVE",
    twoFactorEnabled: false,
    hasPasskey: false,
    passkeyCount: 0,
    hasPin: false,
  },
  session: {
    id: "",
    createdAt: "",
    isLocked: false,
  },
  permissions: [],
  pendingResetRequestsCount: 0,
  isLocked: false,
  setIsLocked: () => {},
  refreshAuth: async () => {},
  logout: async () => {},
  isAuthenticated: false,
  isLoading: false,
  hasPasskey: false,
  passkeyCount: 0,
  hasPin: false,
};

const AdminAuthContext = React.createContext<AdminAuthContextType | null>(null);

export function useAdminAuth() {
  const ctx = React.useContext(AdminAuthContext);
  return ctx || DEFAULT_AUTH_CONTEXT;
}

export interface AdminAuthProviderProps {
  initialSession: {
    user: {
      id: string;
      email: string;
      name: string;
      level: "MAIN_ADMIN" | "SUB_ADMIN";
      role: string;
      status?: string;
      twoFactorEnabled?: boolean;
      webauthnCredentials?: Array<any>;
      pinHash?: string | null;
      displayName?: string;
      jobTitle?: string;
      avatarUrl?: string | null;
      avatarMediaId?: string | null;
      socials?: any;
      createdAt?: string;
      lastLoginAt?: string | null;
    };
    session: {
      id: string;
      device?: string | null;
      browser?: string | null;
      createdAt: string;
      lastActiveAt?: string;
      isLocked?: boolean;
      lockedAt?: string | null;
    };
    permissions?: string[];
    pendingResetRequestsCount?: number;
  };
  children: React.ReactNode;
}

export function AdminAuthProvider({
  initialSession,
  children,
}: AdminAuthProviderProps) {
  const router = useRouter();

  const [user, setUser] = React.useState<AdminAuthUser>(() => ({
    id: initialSession.user.id,
    email: initialSession.user.email,
    name: initialSession.user.name,
    level: initialSession.user.level,
    role: initialSession.user.role,
    status: initialSession.user.status || "ACTIVE",
    twoFactorEnabled: Boolean(initialSession.user.twoFactorEnabled),
    hasPasskey: Boolean(
      initialSession.user.webauthnCredentials &&
        initialSession.user.webauthnCredentials.length > 0
    ),
    passkeyCount: initialSession.user.webauthnCredentials?.length || 0,
    hasPin: Boolean(initialSession.user.pinHash),
    displayName: initialSession.user.displayName,
    jobTitle: initialSession.user.jobTitle,
    avatarUrl: initialSession.user.avatarUrl,
    avatarMediaId: initialSession.user.avatarMediaId,
    socials: initialSession.user.socials,
    createdAt: initialSession.user.createdAt,
    lastLoginAt: initialSession.user.lastLoginAt,
  }));

  const [session, setSession] = React.useState<AdminAuthSession>(() => ({
    id: initialSession.session.id,
    device: initialSession.session.device,
    browser: initialSession.session.browser,
    createdAt: initialSession.session.createdAt,
    lastActiveAt: initialSession.session.lastActiveAt,
    isLocked: Boolean(initialSession.session.isLocked),
    lockedAt: initialSession.session.lockedAt,
  }));

  const [permissions, setPermissions] = React.useState<string[]>(
    initialSession.permissions || []
  );

  const [pendingResetRequestsCount, setPendingResetRequestsCount] =
    React.useState<number>(initialSession.pendingResetRequestsCount || 0);

  const [isLocked, setIsLocked] = React.useState<boolean>(
    Boolean(initialSession.session.isLocked)
  );

  const isLockedRef = React.useRef(isLocked);
  isLockedRef.current = isLocked;

  const isRefreshingRef = React.useRef(false);
  const lastSyncTimeRef = React.useRef<number>(Date.now());

  // Authoritative session refresh: only called on explicit triggers
  const refreshAuth = React.useCallback(async () => {
    if (isRefreshingRef.current) return;
    isRefreshingRef.current = true;
    try {
      const res = await fetch("/api/admin/auth/me", {
        method: "GET",
        credentials: "same-origin",
        cache: "no-store",
      });

      if (res.status === 401) {
        router.push("/admin/login?reason=session_revoked");
        return;
      }

      if (res.ok) {
        const data = await res.json();
        if (data.user) {
          setUser({
            id: data.user.id,
            email: data.user.email,
            name: data.user.name,
            level: data.user.level,
            role: data.user.role,
            status: data.user.status || "ACTIVE",
            twoFactorEnabled: Boolean(data.user.twoFactorEnabled),
            hasPasskey: Boolean(data.user.hasPasskey),
            passkeyCount: data.user.passkeyCount || 0,
            hasPin: Boolean(data.user.hasPin),
            displayName: data.user.displayName,
            jobTitle: data.user.jobTitle,
            avatarUrl: data.user.avatarUrl,
            avatarMediaId: data.user.avatarMediaId,
            socials: data.user.socials,
            createdAt: data.user.createdAt,
            lastLoginAt: data.user.lastLoginAt,
          });
        }
        if (data.session) {
          setSession({
            id: data.session.id,
            device: data.session.device,
            browser: data.session.browser,
            createdAt: data.session.createdAt,
            lastActiveAt: data.session.lastActiveAt,
            isLocked: Boolean(data.session.isLocked),
            lockedAt: data.session.lockedAt,
          });
          setIsLocked(Boolean(data.session.isLocked));
        }
        if (Array.isArray(data.permissions)) {
          setPermissions(data.permissions);
        }
        if (typeof data.pendingResetRequestsCount === "number") {
          setPendingResetRequestsCount(data.pendingResetRequestsCount);
        }
        lastSyncTimeRef.current = Date.now();
      }
    } catch {
      // Network hiccup — fail silently
    } finally {
      isRefreshingRef.current = false;
    }
  }, [router]);

  const logout = React.useCallback(async () => {
    try {
      await fetch("/api/admin/auth/logout", { method: "POST" });
    } catch {}
    router.push("/admin/login");
    router.refresh();
  }, [router]);

  // Gentle session synchronization: checks every 60s when active (NOT 1s or rapid polling)
  React.useEffect(() => {
    const interval = setInterval(() => {
      // If locked, let the lock screen manage unlock state without background ping storms
      if (isLockedRef.current) return;
      refreshAuth();
    }, 60_000);

    // Sync when tab becomes visible if inactive for over 60 seconds
    const handleVisibility = () => {
      if (
        document.visibilityState === "visible" &&
        Date.now() - lastSyncTimeRef.current > 60_000
      ) {
        fetch("/api/admin/security/network-check")
          .then(async (r) => {
            if (r.status === 403) {
              const d = await r.json().catch(() => ({}));
              if (d.code === "NETWORK_BLOCKED") {
                router.push("/admin/login?reason=vpn_blocked");
                return;
              }
            }
            if (!isLockedRef.current) {
              refreshAuth();
            }
          })
          .catch(() => {});
      }
    };

    document.addEventListener("visibilitychange", handleVisibility);

    return () => {
      clearInterval(interval);
      document.removeEventListener("visibilitychange", handleVisibility);
    };
  }, [refreshAuth, router]);

  // Global response listener:
  // - 423: Admin session locked
  // - 403 with code NETWORK_BLOCKED: Session revoked due to VPN/proxy/Tor detection
  React.useEffect(() => {
    if (typeof window === "undefined") return;
    const rawFetch = window.fetch;
    window.fetch = async (input, init) => {
      let finalInit = init;
      const adminLoc = (window as any).__ADMIN_LOCATION__;
      if (adminLoc && typeof input === "string" && input.startsWith("/api/admin")) {
        const headers = new Headers(init?.headers);
        if (!headers.has("x-admin-location")) {
          headers.set("x-admin-location", encodeURIComponent(JSON.stringify(adminLoc)));
        }
        finalInit = { ...init, headers };
      }

      const res = await rawFetch(input, finalInit);
      if (res.status === 423) {
        setIsLocked(true);
      } else if (res.status === 403) {
        try {
          const clone = res.clone();
          clone
            .json()
            .then((body) => {
              if (body && body.code === "NETWORK_BLOCKED") {
                router.push("/admin/login?reason=vpn_blocked");
              }
            })
            .catch(() => {});
        } catch {}
      }
      return res;
    };
    return () => {
      window.fetch = rawFetch;
    };
  }, [router]);

  const value = React.useMemo<AdminAuthContextType>(
    () => ({
      user,
      session,
      permissions,
      pendingResetRequestsCount,
      isLocked,
      setIsLocked,
      refreshAuth,
      logout,
      isAuthenticated: Boolean(user),
      isLoading: false,
      hasPasskey: Boolean(user?.hasPasskey),
      passkeyCount: user?.passkeyCount || 0,
      hasPin: Boolean(user?.hasPin),
    }),
    [
      user,
      session,
      permissions,
      pendingResetRequestsCount,
      isLocked,
      refreshAuth,
      logout,
    ]
  );

  return (
    <AdminAuthContext.Provider value={value}>
      {children}
    </AdminAuthContext.Provider>
  );
}
