import { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { API_BASE_URL, TARGET_ENV, ALLOW_ACTIONPANEL_AI_REQUESTS, setAuthToken, clearAuthToken } from '../constants';
import { usePluginSettings } from './PluginSettingsContext';

interface UserInfo {
  name: string;
  email: string;
  theme: 'system' | 'light' | 'dark';
}

interface AuthContextProps {
  isLoggedIn: boolean;
  userInfo: UserInfo | null;
  login: (email: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
  signup: (name: string, email: string, password: string, verificationCode: string) => Promise<void>;
  updateEmail: (newEmail: string, currentPassword: string) => Promise<{ requiresVerification: boolean }>;
  updatePassword: (currentPassword: string, newPassword: string) => Promise<void>;
  setUserInfo: (info: UserInfo) => void;
  authError: string | null;
  setAuthError: (error: string | null) => void;
  requestVerification: (email: string, purpose: 'registration' | 'password_reset' | 'email_change') => Promise<void>;
  verifyCode: (email: string, code: string) => Promise<boolean>;
  resetPassword: (email: string, code: string, newPassword: string) => Promise<boolean>;
}

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

interface AuthProviderProps {
  children: ReactNode;
}

const reloadHomeRoute = () => {
  try {
    window.history.replaceState(null, '', '#/');
  } catch {
    window.location.hash = '#/';
  }
  window.location.reload();
};

const requestGateMessage = (purpose: string) => (
  `Turn on "Allow WordPress to send requests to ActionPanel AI" in Permissions to ${purpose}.`
);

export const AuthProvider = ({ children }: AuthProviderProps): JSX.Element => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [userInfo, setUserInfo] = useState<UserInfo | null>(null);
  const [authError, setAuthError] = useState<string | null>(null);
  const queryClient = useQueryClient();
  const pluginSettings = usePluginSettings();
  const allowActionPanelAiRequests = TARGET_ENV === 'wordpress'
    ? pluginSettings.allowActionPanelAiRequests
    : ALLOW_ACTIONPANEL_AI_REQUESTS;
  const isPluginAuthBlocked = TARGET_ENV === 'wordpress' && !allowActionPanelAiRequests;

  // Check authentication status on mount
  useEffect(() => {
    const checkAuthStatus = async () => {
      if (isPluginAuthBlocked) {
        setIsLoggedIn(false);
        setUserInfo(null);
        return;
      }

      // console.log('checking auth status');
      let hasRetried = false;

      const fetchStatus = async () => {
        try {
          const response = await fetch(`${API_BASE_URL}/auth-status`, {
            method: 'GET',
            credentials: 'include',
          });

          if (response.status === 401 && !hasRetried) {
            hasRetried = true;
            console.log('Received 401. Retrying auth status check...');
            return await fetchStatus();
          }

          if (response.ok) {
            const data = await response.json();
            setIsLoggedIn(data.isLoggedIn);
          } else {
            setIsLoggedIn(false);
          }
        } catch (error) {
          console.error('Error checking auth status:', error);
          setIsLoggedIn(false);
        }
      };

      await fetchStatus();
    };

    checkAuthStatus();
  }, [isPluginAuthBlocked]);

  // Fetch user info when logged in
  const fetchUserInfo = useCallback(async () => {
    if (isPluginAuthBlocked) {
      setIsLoggedIn(false);
      setUserInfo(null);
      return;
    }

    if (!isLoggedIn) return;

    try {
      const response = await fetch(`${API_BASE_URL}/user-info`, {
        method: 'GET',
        credentials: 'include',
      });

      if (response.ok) {
        const data = await response.json();
        setUserInfo({
          name: data.name,
          email: data.email,
          theme: data.theme,
        });
      } else {
        setIsLoggedIn(false);
        setUserInfo(null);
      }
    } catch (error) {
      console.error('Error fetching user info:', error);
      setIsLoggedIn(false);
      setUserInfo(null);
    }
  }, [isLoggedIn, isPluginAuthBlocked]);

  useEffect(() => {
    fetchUserInfo();
  }, [fetchUserInfo]);

  
  // Login function
  const login = useCallback(
    async (email: string, password: string) => {
      if (isPluginAuthBlocked) {
        const message = requestGateMessage('use login and signup');
        setAuthError(message);
        throw new Error(message);
      }

      setAuthError(null);
      try {
        const response = await fetch(`${API_BASE_URL}/login`, {
          method: 'POST',
          credentials: 'include',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ email, password }),
        });

        if (!response.ok) {
          const errorData = await response.json();
          setAuthError(errorData.detail || 'Failed to log in');
          throw new Error(errorData.detail || 'Failed to log in');
        }

        // Store bearer token in plugin mode to avoid 3rd-party cookie issues
        if (TARGET_ENV === 'wordpress') {
          try {
            const data = await response.json();
            if (data?.access_token) setAuthToken(data.access_token);
          } catch {}
        }

        queryClient.clear();
        window.location.reload();

      } catch (error) {
        console.error('Error during login:', error);
        throw error;
      }
    },
    [queryClient, isPluginAuthBlocked]
  );

  // Logout function
  const logout = useCallback(
    async () => {
      if (isPluginAuthBlocked) {
        clearAuthToken();
        setIsLoggedIn(false);
        setUserInfo(null);
        queryClient.clear();
        reloadHomeRoute();
        return;
      }

      setAuthError(null);
      try {
        const response = await fetch(`${API_BASE_URL}/logout`, {
          method: 'POST',
          credentials: 'include',
        });

        if (!response.ok) {
          const errorData = await response.json();
          setAuthError(errorData.detail || 'Failed to log out');
          throw new Error(errorData.detail || 'Failed to log out');
        }

        // Clear stored bearer token in plugin mode
        if (TARGET_ENV === 'wordpress') {
          clearAuthToken();
        }

        queryClient.clear();
        reloadHomeRoute();
      } catch (error) {
        console.error('Error during logout:', error);
        throw error;
      }
    },
    [queryClient, isPluginAuthBlocked]
  );

  // Signup function
  const signup = useCallback(
    async (name: string, email: string, password: string, verificationCode: string) => {
      if (isPluginAuthBlocked) {
        const message = requestGateMessage('use login and signup');
        setAuthError(message);
        throw new Error(message);
      }

      setAuthError(null);
      try {
        const response = await fetch(`${API_BASE_URL}/register`, {
          method: 'POST',
          credentials: 'include',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            user: {
              name,
              email,
              password,
            },
            verification: {
              email,
              code: verificationCode
            }
          }),
        });

        if (!response.ok) {
          const errorData = await response.json();
          throw new Error(errorData.detail || 'Registration failed');
        }

        if (TARGET_ENV === 'wordpress') {
          try {
            const data = await response.json();
            if (data?.access_token) setAuthToken(data.access_token);
          } catch {}
        }
      
        queryClient.clear();
        window.location.reload();
      } catch (error) {
        const message = error instanceof Error ? error.message : 'Registration failed';
        setAuthError(message);
        throw error;
      }
    },
    [queryClient, isPluginAuthBlocked]
  );

  // Update Email
  const updateEmail = useCallback(
    async (newEmail: string, currentPassword: string) => {
      if (isPluginAuthBlocked) {
        const message = requestGateMessage('use account features');
        setAuthError(message);
        throw new Error(message);
      }

      setAuthError(null);

      try {
        const response = await fetch(`${API_BASE_URL}/account/email`, {
          method: 'PUT',
          credentials: 'include',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ new_email: newEmail, current_password: currentPassword }),
        });

        if (!response.ok) {
          const errorData = await response.json();
          setAuthError(errorData.detail || 'Failed to update email');
          throw new Error(errorData.detail || 'Failed to update email');
        }

        const data = await response.json();
        
        // Only update user info immediately if verification is not required
        if (!data.requires_verification) {
          await fetchUserInfo();
        }

        return { requiresVerification: data.requires_verification };
      } catch (error) {
        console.error('Error updating email:', error);
        throw error;
      }
    },
    [fetchUserInfo, isPluginAuthBlocked]
  );

  // Update Password
  const updatePassword = useCallback(
    async (currentPassword: string, newPassword: string) => {
      if (isPluginAuthBlocked) {
        const message = requestGateMessage('use account features');
        setAuthError(message);
        throw new Error(message);
      }

      setAuthError(null);

      try {
        const response = await fetch(`${API_BASE_URL}/account/password`, {
          method: 'PUT',
          credentials: 'include',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ current_password: currentPassword, new_password: newPassword }),
        });

        if (!response.ok) {
          const errorData = await response.json();
          setAuthError(errorData.detail || 'Failed to update password');
          throw new Error(errorData.detail || 'Failed to update password');
        }

        await fetchUserInfo();
      } catch (error) {
        console.error('Error updating password:', error);
        throw error;
      }
    },
    [fetchUserInfo, isPluginAuthBlocked]
  );

  // Send verification code
  const requestVerification = useCallback(
    async (email: string, purpose: 'registration' | 'password_reset' | 'email_change') => {
      if (isPluginAuthBlocked) {
        const message = requestGateMessage('use login and signup');
        setAuthError(message);
        throw new Error(message);
      }

      try {
        const response = await fetch(`${API_BASE_URL}/request-verification`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ 
            email: email.toLowerCase(),
            purpose: purpose 
          }),
        });

        if (!response.ok) {
          const errorData = await response.json();
          throw new Error(errorData.detail || 'Failed to send verification code');
        }
      } catch (error) {
        const message = error instanceof Error ? error.message : 'Failed to request verification';
        console.error('Error requesting verification:', message);
        throw new Error(message);
      }
    },
    [isPluginAuthBlocked]
  );

  // Verify code
  const verifyCode = useCallback(async (email: string, code: string) => {
    if (isPluginAuthBlocked) {
      const message = requestGateMessage('use account features');
      setAuthError(message);
      return false;
    }

    try {
      const response = await fetch(`${API_BASE_URL}/account/email/verify`, {
        method: 'PUT',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, code }),
      });

      const data = await response.json();

      if (!response.ok) {
        setAuthError(data.detail || 'Failed to verify code');
        throw new Error(data.detail || 'Failed to verify code');
      }

      await fetchUserInfo();
      return true;
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Verification failed';
      setAuthError(message);
      return false;
    }
  }, [fetchUserInfo, isPluginAuthBlocked]);

  const resetPassword = useCallback(
    async (email: string, code: string, newPassword: string) => {
      if (isPluginAuthBlocked) {
        const message = requestGateMessage('use login and signup');
        setAuthError(message);
        throw new Error(message);
      }

      setAuthError(null);
      try {
        const response = await fetch(`${API_BASE_URL}/reset-password`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            email,
            code,
            new_password: newPassword
          }),
        });

        if (!response.ok) {
          const errorData = await response.json();
          throw new Error(errorData.detail || 'Password reset failed');
        }

        return true;
      } catch (error) {
        const message = error instanceof Error ? error.message : 'Password reset failed';
        setAuthError(message);
        throw error;
      }
    },
    [isPluginAuthBlocked]
  );

  const value: AuthContextProps = {
    isLoggedIn,
    userInfo,
    login,
    logout,
    setAuthError,
    signup,
    updateEmail,
    updatePassword,
    setUserInfo,
    authError,
    requestVerification,
    verifyCode,
    resetPassword,
  };

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

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