"use client";

import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from "react";
import type { AuthUser, AuthSession } from "@mosaic/shared";
import { apiGet, apiPost } from "../api/client";

/**
 * Error types for auth session checks
 */
export type AuthErrorType = "network" | "backend" | null;

interface AuthContextValue {
  user: AuthUser | null;
  isLoading: boolean;
  isAuthenticated: boolean;
  authError: AuthErrorType;
  signOut: () => Promise<void>;
  refreshSession: () => Promise<void>;
}

const AuthContext = createContext<AuthContextValue | undefined>(undefined);

/**
 * Check if an error indicates a network/backend issue vs normal "not authenticated"
 */
function isBackendError(error: unknown): { isBackendDown: boolean; errorType: AuthErrorType } {
  // Network errors (fetch failed, DNS, connection refused, etc.)
  if (error instanceof TypeError && error.message.includes("fetch")) {
    return { isBackendDown: true, errorType: "network" };
  }

  // Check for specific error messages that indicate backend issues
  if (error instanceof Error) {
    const message = error.message.toLowerCase();

    // Network-level errors
    if (
      message.includes("network") ||
      message.includes("failed to fetch") ||
      message.includes("connection refused") ||
      message.includes("econnrefused") ||
      message.includes("timeout")
    ) {
      return { isBackendDown: true, errorType: "network" };
    }

    // Backend errors (5xx status codes typically result in these messages)
    if (
      message.includes("internal server error") ||
      message.includes("service unavailable") ||
      message.includes("bad gateway") ||
      message.includes("gateway timeout")
    ) {
      return { isBackendDown: true, errorType: "backend" };
    }
  }

  // Normal auth errors (401, 403, etc.) - user is just not logged in
  return { isBackendDown: false, errorType: null };
}

/**
 * Log auth errors in development mode
 */
function logAuthError(message: string, error: unknown): void {
  if (process.env.NODE_ENV === "development") {
    console.error(`[Auth] ${message}:`, error);
  }
}

export function AuthProvider({ children }: { children: ReactNode }): React.JSX.Element {
  const [user, setUser] = useState<AuthUser | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [authError, setAuthError] = useState<AuthErrorType>(null);

  const checkSession = useCallback(async () => {
    try {
      const session = await apiGet<AuthSession>("/auth/session");
      setUser(session.user);
      setAuthError(null);
    } catch (error) {
      const { isBackendDown, errorType } = isBackendError(error);

      if (isBackendDown) {
        // Backend/network issue - log and expose error to UI
        logAuthError("Session check failed due to backend/network issue", error);
        setAuthError(errorType);
      } else {
        // Normal "not authenticated" state - no logging needed
        setAuthError(null);
      }

      setUser(null);
    } finally {
      setIsLoading(false);
    }
  }, []);

  const signOut = useCallback(async () => {
    try {
      await apiPost("/auth/sign-out");
    } catch (error) {
      console.error("Sign out error:", error);
    } finally {
      setUser(null);
    }
  }, []);

  const refreshSession = useCallback(async () => {
    await checkSession();
  }, [checkSession]);

  useEffect(() => {
    void checkSession();
  }, [checkSession]);

  const value: AuthContextValue = {
    user,
    isLoading,
    isAuthenticated: user !== null,
    authError,
    signOut,
    refreshSession,
  };

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

export function useAuth(): AuthContextValue {
  const context = useContext(AuthContext);
  if (context === undefined) {
    throw new Error("useAuth must be used within AuthProvider");
  }
  return context;
}
