import {
	createContext,
	useCallback,
	useContext,
	useEffect,
	useState,
} from "react";
import { flushSync } from "react-dom";
import { AUTH_PHASES, isAuthPhase } from "../constants/authPhases";

const AuthContext = createContext();

export const useAuth = () => {
	const context = useContext(AuthContext);
	if (!context) {
		throw new Error("useAuth must be used within an AuthProvider");
	}
	return context;
};

export const AuthProvider = ({ children }) => {
	const [user, setUser] = useState(null);
	const [token, setToken] = useState(null);
	const [permissions, setPermissions] = useState(null);
	const [needsFirstTimeSetup, setNeedsFirstTimeSetup] = useState(false);

	// Authentication state machine phases
	const [authPhase, setAuthPhase] = useState(AUTH_PHASES.INITIALISING);
	const [permissionsLoading, setPermissionsLoading] = useState(false);

	// Define functions first
	const fetchPermissions = useCallback(async (authToken) => {
		try {
			setPermissionsLoading(true);
			const response = await fetch("/api/v1/permissions/user-permissions", {
				headers: {
					Authorization: `Bearer ${authToken}`,
				},
			});

			if (response.ok) {
				const data = await response.json();
				setPermissions(data);
				return data;
			} else {
				console.error("Failed to fetch permissions");
				return null;
			}
		} catch (error) {
			console.error("Error fetching permissions:", error);
			return null;
		} finally {
			setPermissionsLoading(false);
		}
	}, []);

	const refreshPermissions = useCallback(async () => {
		if (token) {
			const updatedPermissions = await fetchPermissions(token);
			return updatedPermissions;
		}
		return null;
	}, [token, fetchPermissions]);

	// Initialize auth state from localStorage
	useEffect(() => {
		const storedToken = localStorage.getItem("token");
		const storedUser = localStorage.getItem("user");

		if (storedToken && storedUser) {
			try {
				setToken(storedToken);
				setUser(JSON.parse(storedUser));
				// Fetch permissions from backend
				fetchPermissions(storedToken);
				// User is authenticated, skip setup check
				setAuthPhase(AUTH_PHASES.READY);
			} catch (error) {
				console.error("Error parsing stored user data:", error);
				localStorage.removeItem("token");
				localStorage.removeItem("user");
				// Move to setup check phase
				setAuthPhase(AUTH_PHASES.CHECKING_SETUP);
			}
		} else {
			// No stored auth, check if setup is needed
			setAuthPhase(AUTH_PHASES.CHECKING_SETUP);
		}
	}, [fetchPermissions]);

	const login = async (username, password) => {
		try {
			const response = await fetch("/api/v1/auth/login", {
				method: "POST",
				headers: {
					"Content-Type": "application/json",
				},
				body: JSON.stringify({ username, password }),
			});

			const data = await response.json();

			if (response.ok) {
				// Check if TFA is required
				if (data.requiresTfa) {
					return { success: true, requiresTfa: true };
				}

				// Regular successful login
				setToken(data.token);
				setUser(data.user);
				localStorage.setItem("token", data.token);
				localStorage.setItem("user", JSON.stringify(data.user));

				// Fetch user permissions after successful login
				const userPermissions = await fetchPermissions(data.token);
				if (userPermissions) {
					setPermissions(userPermissions);
				}

				return { success: true };
			} else {
				return { success: false, error: data.error || "Login failed" };
			}
		} catch {
			return { success: false, error: "Network error occurred" };
		}
	};

	const logout = async () => {
		try {
			if (token) {
				await fetch("/api/v1/auth/logout", {
					method: "POST",
					headers: {
						Authorization: `Bearer ${token}`,
						"Content-Type": "application/json",
					},
				});
			}
		} catch (error) {
			console.error("Logout error:", error);
		} finally {
			setToken(null);
			setUser(null);
			setPermissions(null);
			localStorage.removeItem("token");
			localStorage.removeItem("user");
		}
	};

	const updateProfile = async (profileData) => {
		try {
			const response = await fetch("/api/v1/auth/profile", {
				method: "PUT",
				headers: {
					Authorization: `Bearer ${token}`,
					"Content-Type": "application/json",
				},
				body: JSON.stringify(profileData),
			});

			const data = await response.json();

			if (response.ok) {
				setUser(data.user);
				localStorage.setItem("user", JSON.stringify(data.user));
				return { success: true, user: data.user };
			} else {
				return { success: false, error: data.error || "Update failed" };
			}
		} catch {
			return { success: false, error: "Network error occurred" };
		}
	};

	const changePassword = async (currentPassword, newPassword) => {
		try {
			const response = await fetch("/api/v1/auth/change-password", {
				method: "PUT",
				headers: {
					Authorization: `Bearer ${token}`,
					"Content-Type": "application/json",
				},
				body: JSON.stringify({ currentPassword, newPassword }),
			});

			const data = await response.json();

			if (response.ok) {
				return { success: true };
			} else {
				return {
					success: false,
					error: data.error || "Password change failed",
				};
			}
		} catch {
			return { success: false, error: "Network error occurred" };
		}
	};

	const isAdmin = () => {
		return user?.role === "admin";
	};

	// Permission checking functions
	const hasPermission = (permission) => {
		// If permissions are still loading, return false to show loading state
		if (permissionsLoading) {
			return false;
		}
		return permissions?.[permission] === true;
	};

	const canViewDashboard = () => hasPermission("can_view_dashboard");
	const canViewHosts = () => hasPermission("can_view_hosts");
	const canManageHosts = () => hasPermission("can_manage_hosts");
	const canViewPackages = () => hasPermission("can_view_packages");
	const canManagePackages = () => hasPermission("can_manage_packages");
	const canViewUsers = () => hasPermission("can_view_users");
	const canManageUsers = () => hasPermission("can_manage_users");
	const canViewReports = () => hasPermission("can_view_reports");
	const canExportData = () => hasPermission("can_export_data");
	const canManageSettings = () => hasPermission("can_manage_settings");

	// Check if any admin users exist (for first-time setup)
	const checkAdminUsersExist = useCallback(async () => {
		try {
			const response = await fetch("/api/v1/auth/check-admin-users", {
				method: "GET",
				headers: {
					"Content-Type": "application/json",
				},
			});

			if (response.ok) {
				const data = await response.json();
				setNeedsFirstTimeSetup(!data.hasAdminUsers);
				setAuthPhase(AUTH_PHASES.READY); // Setup check complete, move to ready phase
			} else {
				// If endpoint doesn't exist or fails, assume setup is needed
				setNeedsFirstTimeSetup(true);
				setAuthPhase(AUTH_PHASES.READY);
			}
		} catch (error) {
			console.error("Error checking admin users:", error);
			// If there's an error, assume setup is needed
			setNeedsFirstTimeSetup(true);
			setAuthPhase(AUTH_PHASES.READY);
		}
	}, []);

	// Check for admin users ONLY when in CHECKING_SETUP phase
	useEffect(() => {
		if (isAuthPhase.checkingSetup(authPhase)) {
			checkAdminUsersExist();
		}
	}, [authPhase, checkAdminUsersExist]);

	const setAuthState = (authToken, authUser) => {
		// Use flushSync to ensure all state updates are applied synchronously
		flushSync(() => {
			setToken(authToken);
			setUser(authUser);
			setNeedsFirstTimeSetup(false);
			setAuthPhase(AUTH_PHASES.READY);
		});

		// Store in localStorage after state is updated
		localStorage.setItem("token", authToken);
		localStorage.setItem("user", JSON.stringify(authUser));

		// Fetch permissions immediately for the new authenticated user
		fetchPermissions(authToken);
	};

	// Computed loading state based on phase and permissions state
	const isLoading = !isAuthPhase.ready(authPhase) || permissionsLoading;

	// Function to check authentication status (maintains API compatibility)
	const isAuthenticated = () => {
		return !!(user && token && isAuthPhase.ready(authPhase));
	};

	const value = {
		user,
		token,
		permissions,
		isLoading,
		needsFirstTimeSetup,
		authPhase,
		login,
		logout,
		updateProfile,
		changePassword,
		refreshPermissions,
		setAuthState,
		isAuthenticated,
		isAdmin,
		hasPermission,
		canViewDashboard,
		canViewHosts,
		canManageHosts,
		canViewPackages,
		canManagePackages,
		canViewUsers,
		canManageUsers,
		canViewReports,
		canExportData,
		canManageSettings,
	};

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