import { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react';
import { authService, type AuthUser } from '@/lib/auth-service';
import { buildUserFromAuthPayload, type AuthSessionUser } from '@/auth/sessionUser';
import { getAccessToken } from '@/shared/utils/token';
import { Role, Permission, getPermissionsForRoles, hasPermission as checkPermission, hasAnyPermission as checkAnyPermission } from '@/lib/permissions';

// ============================================================================
// TYPES
// ============================================================================

export type User = AuthSessionUser;

interface AuthContextType {
  user: User | null;
  loading: boolean;
  isAuthenticated: boolean;
  login: (
    email: string,
    password: string,
  ) => Promise<{ success: boolean; error?: string; activeRole?: Role }>;
  register: (payload: {
    fullName: string;
    email: string;
    password: string;
    passwordConfirm: string;
    employeeId: string;
    academicTitleCode: string;
    academicTitleOther?: string | null;
    unitId?: string | null;
    unitNameFreetext?: string | null;
    jobTitle: string;
  }) => Promise<
    | { success: true; activeRole: Role }
    | { success: true; needsEmailVerification: true; registeredEmail: string; message: string }
    | { success: false; error?: string }
  >;
  logout: () => Promise<void>;
  hasPermission: (permission: Permission) => boolean;
  hasAnyPermission: (permissions: Permission[]) => boolean;
  hasRole: (role: Role) => boolean;
  // Demo mode functions
  setDemoUser: (role: Role) => void;
  clearDemoUser: () => void;
  isDemoMode: boolean;
  /** Merge fields after profile PATCH (name, phone, email). */
  updateUserFields: (fields: Partial<Pick<User, 'name' | 'email' | 'phone'>>) => void;
  /** Rebuild session user from API auth payload (e.g. after password change). */
  applyAuthUser: (authUser: AuthUser) => { success: boolean; error?: string };
}

// ============================================================================
// CONTEXT
// ============================================================================

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

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

// ============================================================================
// DEMO USERS (for development/testing)
// ============================================================================

const createDemoUser = (role: Role): User => ({
  id: `demo-${role}`,
  email: `${role}@demo.com`,
  name: `Demo ${role.charAt(0).toUpperCase() + role.slice(1)}`,
  phone: null,
  roles: [role],
  availableRoles: [role],
  permissions: getPermissionsForRoles([role]),
});

// ============================================================================
// PROVIDER
// ============================================================================

interface AuthProviderProps {
  children: ReactNode;
}

export function AuthProvider({ children }: AuthProviderProps) {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);
  const [isDemoMode, setIsDemoMode] = useState(false);

  // Check for existing session on mount
  useEffect(() => {
    const initAuth = async () => {
      // Check for demo user in localStorage first
      const demoRole = localStorage.getItem('demo-user-role') as Role | null;
      if (demoRole && ['admin', 'editor', 'viewer'].includes(demoRole)) {
        setUser(createDemoUser(demoRole));
        setIsDemoMode(true);
        setLoading(false);
        return;
      }

      // Restore JWT session from localStorage
      if (getAccessToken()) {
        const result = await authService.refreshSession();
        if (result.success && result.user) {
          const sessionUser = buildUserFromAuthPayload(result.user);
          if (sessionUser) {
            setUser(sessionUser);
            setIsDemoMode(false);
          }
        }
      }
      setLoading(false);
    };

    initAuth();
  }, []);

  const login = useCallback(async (email: string, password: string) => {
    const result = await authService.login(email, password);
    if (result.success && result.user) {
      const sessionUser = buildUserFromAuthPayload(result.user);
      if (!sessionUser) {
        return { success: false as const, error: 'Tài khoản không có vai trò hợp lệ.' };
      }
      setUser(sessionUser);
      setIsDemoMode(false);
      localStorage.removeItem('demo-user-role');
      return { success: true as const, activeRole: sessionUser.roles[0] };
    }
    return { success: false as const, error: result.error || 'Đăng nhập thất bại' };
  }, []);

  const register = useCallback(
    async (payload: {
      fullName: string;
      email: string;
      password: string;
      passwordConfirm: string;
      employeeId: string;
      academicTitleCode: string;
      academicTitleOther?: string | null;
      unitId?: string | null;
      unitNameFreetext?: string | null;
      jobTitle: string;
    }) => {
      const result = await authService.register(payload);
      if (!result.success) {
        return { success: false as const, error: result.error || 'Đăng ký thất bại' };
      }
      if ('emailVerificationRequired' in result && result.emailVerificationRequired) {
        return {
          success: true as const,
          needsEmailVerification: true as const,
          registeredEmail: result.email,
          message: result.message || '',
        };
      }
      const sessionUser = buildUserFromAuthPayload(result.user);
      if (!sessionUser) {
        return { success: false as const, error: 'Tài khoản không có vai trò hợp lệ.' };
      }
      setUser(sessionUser);
      setIsDemoMode(false);
      localStorage.removeItem('demo-user-role');
      return { success: true as const, activeRole: sessionUser.roles[0] };
    },
    [],
  );

  const logout = useCallback(async () => {
    if (!isDemoMode) {
      await authService.logout();
    }
    setUser(null);
    setIsDemoMode(false);
    localStorage.removeItem('demo-user-role');
  }, [isDemoMode]);

  const setDemoUser = useCallback((role: Role) => {
    const demoUser = createDemoUser(role);
    setUser(demoUser);
    setIsDemoMode(true);
    localStorage.setItem('demo-user-role', role);
  }, []);

  const clearDemoUser = useCallback(() => {
    setUser(null);
    setIsDemoMode(false);
    localStorage.removeItem('demo-user-role');
  }, []);

  const hasPermission = useCallback((permission: Permission) => {
    if (!user) return false;
    return checkPermission(user.roles, permission);
  }, [user]);

  const hasAnyPermission = useCallback((permissions: Permission[]) => {
    if (!user) return false;
    return checkAnyPermission(user.roles, permissions);
  }, [user]);

  const hasRole = useCallback((role: Role) => {
    if (!user) return false;
    return user.roles.includes(role);
  }, [user]);

  const updateUserFields = useCallback((fields: Partial<Pick<User, 'name' | 'email' | 'phone'>>) => {
    setUser((u) => (u ? { ...u, ...fields } : null));
  }, []);

  const applyAuthUser = useCallback((authUser: AuthUser) => {
    const sessionUser = buildUserFromAuthPayload(authUser);
    if (!sessionUser) {
      return { success: false as const, error: 'Không thể cập nhật phiên.' };
    }
    setUser(sessionUser);
    return { success: true as const };
  }, []);

  const value: AuthContextType = {
    user,
    loading,
    isAuthenticated: !!user,
    login,
    register,
    logout,
    hasPermission,
    hasAnyPermission,
    hasRole,
    setDemoUser,
    clearDemoUser,
    isDemoMode,
    updateUserFields,
    applyAuthUser,
  };

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