import React, { createContext, useContext, useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { storage } from '../lib/storage';
import { Module, Role } from '../types';

interface UserProfile {
  uid: string;
  name: string;
  email: string;
  role: string;
  tenantId?: string;
  photoURL?: string;
  createdAt: string;
}

const MODULES: Module[] = [
  { id: 'dashboard', name: 'Dashboard', description: 'Main Dashboard', actions: ['view'] },
  { id: 'crm', name: 'CRM', description: 'Customer Relationship Management', actions: ['view', 'create', 'edit', 'delete', 'export'] },
  { id: 'projects', name: 'Projects', description: 'Project Management', actions: ['view', 'view_all', 'create', 'edit', 'delete', 'export'] },
  { id: 'tasks', name: 'Tasks', description: 'Tasks & Timesheets', actions: ['view', 'view_all', 'create', 'edit', 'delete', 'export'] },
  { id: 'finance', name: 'Finance', description: 'Financial Management', actions: ['view', 'create', 'edit', 'delete', 'export'] },
  { id: 'hr', name: 'HR', description: 'Human Resources', actions: ['view', 'create', 'edit', 'delete', 'export'] },
  { id: 'operations', name: 'Operations', description: 'Operations Control', actions: ['view', 'create', 'edit', 'delete', 'export'] },
  { id: 'documents', name: 'Documents', description: 'Document Management', actions: ['view', 'create', 'edit', 'delete', 'export'] },
  { id: 'settings', name: 'Settings', description: 'System Settings', actions: ['view', 'edit'] },
];

interface AuthContextType {
  user: any | null;
  profile: UserProfile | null;
  loading: boolean;
  isAdmin: boolean;
  rolePermissions: Record<string, string[]>;
  roles: RoleDefinition[];
  systemUsers: any[];
  modules: Module[];
  login: (username: string, password: string) => Promise<void>;
  logout: () => void;
  hasPermission: (permissionId: string) => boolean;
  updateRolePermissions: (permissions: Record<string, string[]>) => Promise<void>;
  updateRoles: (roles: RoleDefinition[]) => Promise<void>;
  updateSystemUsers: (users: any[]) => Promise<void>;
  refreshUsers: () => Promise<void>;
}

interface RoleDefinition {
  name: string;
  description: string;
  users?: number;
}

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

export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [user, setUser] = useState<any | null>(null);
  const [profile, setProfile] = useState<UserProfile | null>(null);
  const [loading, setLoading] = useState(true);
  const [roles, setRoles] = useState<RoleDefinition[]>([
    { name: 'Administrator', description: 'Full system access and configuration', users: 0 },
    { name: 'Manager', description: 'Access to departmental reports and tasks', users: 0 },
    { name: 'Employee', description: 'Standard access to personal tasks and documents', users: 0 },
    { name: 'Guest', description: 'Limited read-only access to specific projects', users: 0 },
  ]);
  const [systemUsers, setSystemUsers] = useState<any[]>([]);
  const [rolePermissions, setRolePermissions] = useState<Record<string, string[]>>({
    'Administrator': [
      'dashboard.view',
      'crm.view', 'crm.create', 'crm.edit', 'crm.delete', 'crm.export',
      'projects.view', 'projects.view_all', 'projects.create', 'projects.edit', 'projects.delete', 'projects.export',
      'tasks.view', 'tasks.view_all', 'tasks.create', 'tasks.edit', 'tasks.delete', 'tasks.export',
      'finance.view', 'finance.create', 'finance.edit', 'finance.delete', 'finance.export',
      'hr.view', 'hr.create', 'hr.edit', 'hr.delete', 'hr.export',
      'operations.view', 'operations.create', 'operations.edit', 'operations.delete', 'operations.export',
      'documents.view', 'documents.create', 'documents.edit', 'documents.delete', 'documents.export',
      'settings.view', 'settings.edit'
    ],
    'Manager': [
      'dashboard.view',
      'crm.view', 'crm.create', 'crm.edit',
      'projects.view', 'projects.view_all', 'projects.create', 'projects.edit',
      'tasks.view', 'tasks.view_all', 'tasks.create', 'tasks.edit',
      'hr.view',
      'operations.view',
      'documents.view', 'documents.create'
    ],
    'Employee': [
      'dashboard.view',
      'projects.view',
      'tasks.view',
      'documents.view'
    ],
  });

  const lastSyncTime = useRef<number>(0);
  const isSyncing = useRef<boolean>(false);
  const pendingSyncs = useRef<Set<string>>(new Set());

  const initAuth = useCallback(async (force = false, targetKey?: string) => {
    if (isSyncing.current) {
      pendingSyncs.current.add(targetKey || 'all');
      return;
    }

    isSyncing.current = true;
    try {
      // Check health for last change
      const healthRes = await fetch(`/api/health?t=${Date.now()}`, {
        credentials: 'include'
      });
      if (healthRes.ok) {
        const health = await healthRes.json();
        if (!force && health.lastChange <= lastSyncTime.current) return;
        lastSyncTime.current = health.lastChange;
      }

      if (targetKey) {
        const normalizedKey = targetKey.toLowerCase();
        console.log(`[AuthContext] Syncing targeted key: ${targetKey}`);
        
        if (normalizedKey === 'rolepermissions') {
          const savedPermissions = await storage.get('rolePermissions', null);
          if (savedPermissions) {
            setRolePermissions(prev => {
               // Deep compare to avoid unnecessary re-renders if needed, 
               // but ensure we update with the full set including new roles
               return savedPermissions;
            });
          }
        } else if (normalizedKey === 'roles') {
          const savedRoles = await storage.get('roles', null);
          if (savedRoles) setRoles(savedRoles);
        } else if (normalizedKey === 'users') {
          // Sync system users list
          const usersData = await storage.get('users', []);
          setSystemUsers(usersData);

          // Find current user in the refreshed list and update profile if needed
          setUser(userData => {
            if (!userData) return null;
            const updatedProfile = usersData.find((u: any) => u.uid === userData.uid || u.id === userData.uid);
            
            if (updatedProfile) {
              const newProfile: UserProfile = {
                uid: updatedProfile.uid || updatedProfile.id,
                name: updatedProfile.name,
                email: updatedProfile.email,
                role: updatedProfile.role,
                tenantId: updatedProfile.tenantId,
                createdAt: updatedProfile.createdAt
              };

              // Only update if something actually changed
              if (JSON.stringify(newProfile) !== JSON.stringify(userData.profile)) {
                console.log('[AuthContext] Updating current profile from master list');
                const nextUser = { ...userData, profile: newProfile };
                setProfile(newProfile);
                // Also update session on server to persist across refreshes
                storage.setUser(nextUser);
                return nextUser;
              }
            }
            return userData;
          });
        }
      } else {
        console.log('[AuthContext] Syncing all auth data');
        const [savedUser, savedPermissions, savedRoles, usersData] = await Promise.all([
          storage.getUser(),
          storage.get('rolePermissions', null),
          storage.get('roles', null),
          storage.get('users', [])
        ]);
        
        if (savedUser) {
          setUser(savedUser);
          setProfile(savedUser.profile);
        }

        if (usersData) {
          setSystemUsers(usersData);
        }
        
        if (savedPermissions) {
          setRolePermissions(savedPermissions);
        }

        if (savedRoles) {
          setRoles(savedRoles);
        }
      }
    } catch (err) {
      console.error('[AuthContext] Initialization error:', err);
    } finally {
      setLoading(false);
      isSyncing.current = false;
      if (pendingSyncs.current.size > 0) {
        const nextSyncs = Array.from(pendingSyncs.current);
        pendingSyncs.current.clear();
        const nextKey = nextSyncs.includes('all') ? undefined : nextSyncs[nextSyncs.length - 1];
        console.log(`[AuthContext] Executing queued sync for: ${nextKey || 'all'}`);
        setTimeout(() => initAuth(false, nextKey), 100);
      }
    }
  }, []);

  useEffect(() => {
    initAuth(true);
  }, [initAuth]);

  // Replacement for Socket.io: Periodic polling for data changes
  useEffect(() => {
    if (!user) return;

    console.log('[AuthContext] Initializing polling for auth updates...');
    const pollInterval = setInterval(() => {
      initAuth(false);
    }, 10000); // Poll every 10 seconds

    return () => {
      clearInterval(pollInterval);
    };
  }, [user, initAuth]);

  const updateRolePermissions = useCallback(async (permissions: Record<string, string[]>) => {
    setRolePermissions(permissions);
    const lastChange = await storage.set('rolePermissions', permissions);
    if (typeof lastChange === 'number') lastSyncTime.current = lastChange;
  }, []);

  const updateRoles = useCallback(async (newRoles: RoleDefinition[]) => {
    setRoles(newRoles);
    const lastChange = await storage.set('roles', newRoles);
    if (typeof lastChange === 'number') lastSyncTime.current = lastChange;
  }, []);

  const updateSystemUsers = useCallback(async (newUsers: any[]) => {
    setSystemUsers(newUsers);
    const lastChange = await storage.set('users', newUsers);
    if (typeof lastChange === 'number') lastSyncTime.current = lastChange;
  }, []);

  const refreshUsers = useCallback(async () => {
    storage.clearCache('users');
    const usersData = await storage.get('users', []);
    setSystemUsers(usersData);
  }, []);

  const hasPermission = useCallback((permissionId: string) => {
    if (!profile) return false;
    
    // Super-admin bypass for the hardcoded system admin
    if (profile.uid === 'admin-123') return true;
    
    const permissions = rolePermissions[profile.role] || [];
    return permissions.includes(permissionId);
  }, [profile, rolePermissions]);

  const login = useCallback(async (username: string, password: string) => {
    // 1. Check hardcoded admin
    if (username.toLowerCase() === 'admin' && (password === 'admin' || password === 'AdminPassword123!')) {
      const adminProfile: UserProfile = {
        uid: 'admin-123',
        name: 'System Administrator',
        email: 'admin@app.local',
        role: 'Administrator',
        createdAt: new Date().toISOString()
      };
      const userData = { uid: 'admin-123', email: 'admin@app.local', profile: adminProfile, username: 'admin' };
      setUser(userData);
      setProfile(adminProfile);
      await storage.setUser(userData);
      return;
    }

    // 2. Check users in storage
    const users = await storage.get('users', []);
    const foundUser = users.find((u: any) => 
      (u.username === username || u.email === username) && u.password === password
    );

    if (foundUser) {
      if (foundUser.status === 'Pending') {
        throw new Error('Your account is pending activation. Please contact an administrator.');
      }
      if (foundUser.status === 'Inactive') {
        throw new Error('Your account has been deactivated.');
      }

      const userProfile: UserProfile = {
        uid: foundUser.uid,
        name: foundUser.name,
        email: foundUser.email,
        role: foundUser.role,
        tenantId: foundUser.tenantId,
        createdAt: foundUser.createdAt
      };
      const userData = { uid: foundUser.uid, email: foundUser.email, profile: userProfile, username: foundUser.username };
      setUser(userData);
      setProfile(userProfile);
      await storage.setUser(userData);
    } else {
      throw new Error('Invalid username or password');
    }
  }, []);

  const logout = useCallback(async () => {
    setUser(null);
    setProfile(null);
    await storage.logout();
  }, []);

  const value = useMemo(() => ({
    user,
    profile,
    loading,
    isAdmin: profile?.role === 'Administrator',
    rolePermissions,
    roles,
    systemUsers,
    modules: MODULES,
    login,
    logout,
    hasPermission,
    updateRolePermissions,
    updateRoles,
    updateSystemUsers,
    refreshUsers
  }), [user, profile, loading, rolePermissions, roles, systemUsers, login, logout, hasPermission, updateRolePermissions, updateRoles, updateSystemUsers, refreshUsers]);

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

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