import React, { createContext, useContext, useEffect, useState, useRef, type ReactNode } from 'react';
import { api } from '../services/api';
import { authEvents } from '../services/authState';
import {
    Dialog,
    DialogTitle,
    DialogContent,
    DialogActions,
    Button,
    Typography,
} from '@mui/material';
import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';

interface AuthContextType {
    token: string | null;
    isAuthenticated: boolean;
    isLoading: boolean;
    login: (token: string) => Promise<void>;
    logout: () => void;
}

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

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

interface AuthProviderProps {
    children: ReactNode;
}

// Extract token from path like /login/xxxx or /login/xxxx/...
const extractTokenFromPath = (pathname: string): string | null => {
    const loginPathMatch = pathname.match(/^\/login\/([^\/]+)\/?/);
    return loginPathMatch ? loginPathMatch[1] : null;
};

// Auth prompt dialog component
const AuthPromptDialog: React.FC<{
    open: boolean;
    onGoToLogin: () => void;
}> = ({ open, onGoToLogin }) => {
    return (
        <Dialog
            open={open}
            onClose={() => {}}
            maxWidth="sm"
            fullWidth
            PaperProps={{
                sx: {
                    borderRadius: 2,
                    boxShadow: '0 8px 32px rgba(0,0,0,0.1)',
                }
            }}
        >
            <DialogTitle sx={{
                display: 'flex',
                alignItems: 'center',
                gap: 1,
                pb: 1,
            }}>
                <ErrorOutlineIcon color="warning" sx={{ fontSize: 28 }} />
                <Typography variant="h6" component="span">
                    Session Expired
                </Typography>
            </DialogTitle>
            <DialogContent>
                <Typography variant="body1" color="text.secondary">
                    Your authentication token has expired or is invalid. Please log in again to continue.
                </Typography>
            </DialogContent>
            <DialogActions sx={{ px: 3, pb: 2 }}>
                <Button
                    variant="contained"
                    onClick={onGoToLogin}
                    sx={{ minWidth: 120 }}
                >
                    Go to Login
                </Button>
            </DialogActions>
        </Dialog>
    );
};

export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
    const [token, setToken] = useState<string | null>(null);
    const [isLoading, setIsLoading] = useState(true);
    const [authPromptOpen, setAuthPromptOpen] = useState(false);

    // Track whether initialization is complete
    // This prevents showing the auth dialog during initial token validation
    const isInitializingRef = useRef(true);

    // Check both state and localStorage for authentication
    // This prevents race conditions where state hasn't updated yet but token is in storage
    const isAuthenticated = !!token || !!localStorage.getItem('user_auth_token');

    const login = async (newToken: string) => {
        setToken(newToken);
        localStorage.setItem('user_auth_token', newToken);
        setAuthPromptOpen(false);
        // Initialize API instances with the new token
        await api.initialize();
    };

    const logout = () => {
        setToken(null);
        localStorage.removeItem('user_auth_token');
    };

    const handleGoToLogin = () => {
        setAuthPromptOpen(false);
        // Save current location for redirect after login
        const currentPath = window.location.pathname + window.location.search + window.location.hash;
        sessionStorage.setItem('redirectAfterLogin', currentPath);
        window.location.href = '/login';
    };

    useEffect(() => {
        const initializeAuth = async () => {
            try {
                // Check if we're on the login page with a token path
                // If so, skip AuthContext initialization and let Login component handle it
                if (extractTokenFromPath(window.location.pathname)) {
                    // Mark initialization as complete immediately to avoid showing auth prompt
                    isInitializingRef.current = false;
                    setIsLoading(false);
                    return;
                }

                // Check localStorage for stored token
                const storedToken = localStorage.getItem('user_auth_token');
                let finalToken = null;

                if (storedToken) {
                    finalToken = storedToken;
                }

                // Validate token by making a test API call to the validate endpoint
                if (finalToken && finalToken.trim() !== '') {
                    try {
                        const response = await fetch('/api/v1/auth/validate', {
                            headers: {
                                'Authorization': `Bearer ${finalToken}`,
                                'Content-Type': 'application/json',
                            },
                        });

                        if (response.ok) {
                            // Token is valid
                            setToken(finalToken);
                            await api.initialize();
                        } else {
                            // Token is invalid
                            localStorage.removeItem('user_auth_token');
                        }
                    } catch (validateError) {
                        // Validation request failed (network error, server error, etc.)
                        // Don't clear the token - it might be a temporary issue
                        console.error('Token validation error:', validateError);
                        // Set the token anyway - API calls will handle 401s later
                        setToken(finalToken);
                        await api.initialize();
                    }
                }
            } catch (error) {
                console.error('Auth initialization error:', error);
                // Don't remove token on general errors - might be temporary
            } finally {
                // Mark initialization as complete
                isInitializingRef.current = false;
                setIsLoading(false);
            }
        };

        initializeAuth();
    }, []);

    // Listen for auth failure events from API layer (401 responses)
    useEffect(() => {
        const unsubscribe = authEvents.onAuthFailure(() => {
            // Only show prompt if:
            // 1. Initialization is complete (don't show for initial invalid token)
            // 2. Not already on login page
            if (!isInitializingRef.current && window.location.pathname !== '/login') {
                setToken(null);
                setAuthPromptOpen(true);
            }
        });

        // Storage event for cross-tab sync
        const handleStorageChange = (e: StorageEvent) => {
            if (e.key === 'user_auth_token') {
                if (e.newValue === null) {
                    setToken(null);
                } else if (e.newValue && e.newValue.trim() !== '') {
                    setToken(e.newValue);
                }
            }
        };

        // Custom event for additional cross-tab compatibility
        const handleAuthStateChange = (e: CustomEvent<{ type: 'logout' | 'login'; token?: string }>) => {
            if (e.detail.type === 'logout') {
                setToken(null);
            } else if (e.detail.type === 'login' && e.detail.token) {
                setToken(e.detail.token);
            }
        };

        window.addEventListener('storage', handleStorageChange);
        window.addEventListener('auth-state-change', handleAuthStateChange as EventListener);

        return () => {
            unsubscribe();
            window.removeEventListener('storage', handleStorageChange);
            window.removeEventListener('auth-state-change', handleAuthStateChange as EventListener);
        };
    }, []);

    return (
        <AuthContext.Provider value={{ token, isAuthenticated, isLoading, login, logout }}>
            {children}
            <AuthPromptDialog open={authPromptOpen} onGoToLogin={handleGoToLogin} />
        </AuthContext.Provider>
    );
};
