import React, { createContext, useContext, useCallback, useMemo } from 'react';
import { useQuery, useQueryClient, type UseQueryResult } from '@tanstack/react-query';
import { authApi } from '@/api/auth';
import type { User, AuthState, SignupData, CompanyRole, CompanyPermission } from '@/types';

// ─── Role hierarchy ───────────────────────────────────────────────────
const ROLE_LEVEL: Record<CompanyRole, number> = {
  owner: 5,
  admin: 4,
  manager: 3,
  rep: 2,
  viewer: 1,
};

// ─── Permission matrix ────────────────────────────────────────────────
// Maps each permission to the minimum role level required.
const PERMISSION_MIN_LEVEL: Record<CompanyPermission, number> = {
  create_org: ROLE_LEVEL.owner,           // Only owner
  manage_team: ROLE_LEVEL.manager,        // owner, admin, manager
  view_analytics: ROLE_LEVEL.manager,     // owner, admin, manager
  edit_integrations: ROLE_LEVEL.admin,    // owner, admin
  view_reports: ROLE_LEVEL.viewer,        // Everyone (rep+ for own, viewer+ for read-only)
  edit_settings: ROLE_LEVEL.admin,        // owner, admin
};

// ─── Check if role meets minimum level ─────────────────────────────────
function roleMeetsMinimum(role: CompanyRole | undefined, minLevel: number): boolean {
  if (!role) return false;
  return (ROLE_LEVEL[role] ?? 0) >= minLevel;
}

// ─── Context value ─────────────────────────────────────────────────────
const AuthContext = createContext<AuthState | undefined>(undefined);

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const queryClient = useQueryClient();

  // ─── User data managed by React Query ────────────────────────────────
  // staleTime of 5 min means repeated renders won't trigger refetches;
  // any mutation that changes user data invalidates the cache.
  const query: UseQueryResult<User | null, Error> = useQuery({
    queryKey: ['auth-user'],
    queryFn: authApi.getCurrentUser,
    staleTime: 5 * 60 * 1000,
    retry: false,
  });

  const user = query.data ?? null;
  const isLoading = query.isLoading;

  const login = useCallback(async (email: string, password: string) => {
    await authApi.login(email, password);
    // Invalidate so the cached user refetches with the new session
    await queryClient.invalidateQueries({ queryKey: ['auth-user'] });
  }, [queryClient]);

  const logout = useCallback(async () => {
    await authApi.logout();
    // Clear cached user data so all consumers immediately see logged-out state
    queryClient.setQueryData(['auth-user'], null);
  }, [queryClient]);

  const signup = useCallback(async (data: SignupData) => {
    await authApi.signup(data);
    await queryClient.invalidateQueries({ queryKey: ['auth-user'] });
  }, [queryClient]);

  const updateProfile = useCallback(async (full_name: string) => {
    await authApi.updateProfile(full_name);
    await queryClient.invalidateQueries({ queryKey: ['auth-user'] });
  }, [queryClient]);

  const changePassword = useCallback(async (currentPassword: string, newPassword: string) => {
    return await authApi.changePassword(currentPassword, newPassword);
  }, []);

  const isRole = useCallback((role: string): boolean => {
    return user?.role === role;
  }, [user]);

  const hasRole = useCallback((...roles: string[]): boolean => {
    return !!user?.role && roles.includes(user.role);
  }, [user]);

  // ─── Company role helpers ─────────────────────────────────────────────
  const getCompanyRole = useCallback((): CompanyRole | undefined => {
    return user?.companyRole;
  }, [user]);

  const getRoleLevel = useCallback((): number => {
    return ROLE_LEVEL[user?.companyRole as CompanyRole] ?? 0;
  }, [user]);

  const hasCompanyPermission = useCallback((permission: CompanyPermission): boolean => {
    const required = PERMISSION_MIN_LEVEL[permission];
    return roleMeetsMinimum(user?.companyRole as CompanyRole, required);
  }, [user]);

  const hasRoleAtLeast = useCallback((minRole: CompanyRole): boolean => {
    const required = ROLE_LEVEL[minRole];
    return roleMeetsMinimum(user?.companyRole as CompanyRole, required);
  }, [user]);

  const value: AuthState = useMemo(() => ({
    user,
    isAuthenticated: !!user,
    isLoading,
    login,
    logout,
    signup,
    updateProfile,
    changePassword,
    isRole,
    hasRole,
    // Company role enforcement
    companyRole: getCompanyRole(),
    roleLevel: getRoleLevel(),
    hasCompanyPermission,
    hasRoleAtLeast,
  }), [user, isLoading, login, logout, signup, updateProfile, changePassword, isRole, hasRole,
       getCompanyRole, getRoleLevel, hasCompanyPermission, hasRoleAtLeast]);

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

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