import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { Session, User } from '@supabase/supabase-js';
import { CCUser, CCUserMetadata, authService } from '../services/auth/authService';
import { logger } from '../debugConfig';
import { supabase } from '../supabaseClient';
import { storageService, StorageKeys } from '../services/auth/localStorageService';

export interface AuthContextType {
  user: CCUser | null;
  user_role: string | null;
  accessToken: string | null;
  loading: boolean;
  error: Error | null;
  signIn: (email: string, password: string) => Promise<void>;
  signOut: () => Promise<void>;
  clearError: () => void;
}

export const AuthContext = createContext<AuthContextType>({
  user: null,
  user_role: null,
  accessToken: null,
  loading: true,
  error: null,
  signIn: async () => {},
  signOut: async () => {},
  clearError: () => {}
});

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const navigate = useNavigate();
  const [user, setUser] = useState<CCUser | null>(null);
  const [user_role, setUserRole] = useState<string | null>(null);
  const [accessToken, setAccessToken] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<Error | null>(null);

  const apiBase = import.meta.env.VITE_API_BASE as string;

  const persistSession = useCallback((session: Session | null) => {
    if (session) {
      storageService.set(StorageKeys.SUPABASE_SESSION, session);
    } else {
      storageService.remove(StorageKeys.SUPABASE_SESSION);
    }
  }, []);

  const buildUserFromSupabase = useCallback(async (supabaseUser: User | null): Promise<{ user: CCUser | null; role: string | null }> => {
    if (!supabaseUser) {
      return { user: null, role: null };
    }

    const metadata = supabaseUser.user_metadata as CCUserMetadata;
    const baseUsername = metadata.username || metadata.preferred_username || metadata.email?.split('@')[0] || supabaseUser.email?.split('@')[0] || 'user';
    const baseDisplayName = metadata.display_name || metadata.name || metadata.preferred_username || baseUsername;
    const userType = (metadata.user_type || 'email_teacher').trim();

    const resolvedUser: CCUser = {
      id: supabaseUser.id,
      email: supabaseUser.email,
      user_type: userType,
      username: baseUsername,
      display_name: baseDisplayName,
      school_id: null,
      created_at: supabaseUser.created_at,
      updated_at: supabaseUser.updated_at
    };

    const resolvedRole = metadata.user_role || userType || null;
    return { user: resolvedUser, role: resolvedRole };
  }, []);

  const triggerUserInit = useCallback((token: string) => {
    fetch(`${apiBase}/user/init`, {
      method: 'POST',
      headers: { Authorization: `Bearer ${token}` },
    })
      .then(r => r.json())
      .then(data => logger.debug('auth-context', '✅ User init', data))
      .catch(err => logger.warn('auth-context', '⚠️ User init failed', { err }));
  }, [apiBase]);

  useEffect(() => {
    const { data: { subscription } } = supabase.auth.onAuthStateChange(
      async (event, session) => {
        logger.debug('auth-context', '🔄 Auth state change', { event, hasSession: !!session });

        if (event === 'SIGNED_IN') {
          persistSession(session ?? null);
          if (session?.user) {
            try {
              const { user: resolvedUser, role } = await buildUserFromSupabase(session.user);
              setUser(resolvedUser);
              setUserRole(role);
              setAccessToken(session.access_token ?? null);
              triggerUserInit(session.access_token);
            } catch (buildError) {
              logger.error('auth-context', '❌ Failed to build user from session', { event, error: buildError });
              setUser(null);
              setUserRole(null);
              setAccessToken(null);
              setError(buildError instanceof Error ? buildError : new Error('Failed to load user'));
            }
          } else {
            setUser(null);
            setUserRole(null);
            setAccessToken(null);
          }
          setLoading(false);
          return;
        }

        if (event === 'INITIAL_SESSION' || event === 'TOKEN_REFRESHED') {
          persistSession(session ?? null);
          if (session?.user) {
            try {
              const { user: resolvedUser, role } = await buildUserFromSupabase(session.user);
              setUser(resolvedUser);
              setUserRole(role);
              setAccessToken(session.access_token ?? null);
            } catch (buildError) {
              logger.error('auth-context', '❌ Failed to build user from session', { event, error: buildError });
              setUser(null);
              setUserRole(null);
              setAccessToken(null);
              setError(buildError instanceof Error ? buildError : new Error('Failed to load user'));
            }
          } else {
            setUser(null);
            setUserRole(null);
            setAccessToken(null);
          }
          setLoading(false);
          return;
        }

        if (event === 'SIGNED_OUT') {
          persistSession(null);
          setUser(null);
          setUserRole(null);
          setAccessToken(null);
          setLoading(false);
        }
      }
    );

    return () => subscription.unsubscribe();
  }, [buildUserFromSupabase, persistSession, triggerUserInit]);

  const signIn = async (email: string, password: string) => {
    try {
      setLoading(true);
      const { data, error: signInError } = await supabase.auth.signInWithPassword({
        email,
        password
      });

      if (signInError) throw signInError;

      if (data.session) {
        persistSession(data.session);
      }

      if (data.user) {
          const { user: resolvedUser, role } = await buildUserFromSupabase(data.user);
          setUser(resolvedUser);
          setUserRole(role);
          setAccessToken(data.session?.access_token ?? null);
      }
    } catch (error) {
      logger.error('auth-context', '❌ Sign in failed', { error });
      setError(error instanceof Error ? error : new Error('Sign in failed'));
      throw error;
    } finally {
      setLoading(false);
    }
  };

  const signOut = async () => {
    try {
      setLoading(true);
      await authService.logout();
      persistSession(null);
      setUser(null);
      navigate('/');
    } catch (error) {
      logger.error('auth-context', '❌ Sign out failed', { error });
      setError(error instanceof Error ? error : new Error('Sign out failed'));
      throw error;
    } finally {
      setLoading(false);
    }
  };

  const clearError = () => setError(null);

  return (
    <AuthContext.Provider
      value={{
        user,
        user_role,
        accessToken,
        loading,
        error,
        signIn,
        signOut,
        clearError
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}

export const useAuth = () => useContext(AuthContext);
