import React, { createContext, useState, useEffect, useCallback } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import api, { setOnUnauthorized } from '../config/api';
import { User, Role } from '../types';

export type UserRole = 'SUPER_ADMIN' | 'COMPANY_ADMIN' | 'MANAGER' | 'SUPERVISOR' | 'TECHNICIAN' | 'EMPLOYEE' | 'VIEWER';

interface AuthContextType {
  user: (User & { role_names?: string[]; permissions?: string[] }) | null;
  token: string | null;
  loading: boolean;
  isAuthenticated: boolean;
  isAdmin: boolean;
  login: (email: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
  hasPermission: (key: string) => boolean;
  hasRole: (...roles: string[]) => boolean;
  refreshUser: () => Promise<void>;
}

export const AuthContext = createContext<AuthContextType>({
  user: null,
  token: null,
  loading: true,
  isAuthenticated: false,
  isAdmin: false,
  login: async () => {},
  logout: async () => {},
  hasPermission: () => false,
  hasRole: () => false,
  refreshUser: async () => {},
});

const ADMIN_ROLES = ['SUPER_ADMIN', 'COMPANY_ADMIN'];

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<(User & { role_names?: string[]; permissions?: string[] }) | null>(null);
  const [token, setToken] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    loadStoredAuth();
    setOnUnauthorized(() => {
      setToken(null);
      setUser(null);
    });
  }, []);

  const loadStoredAuth = async () => {
    try {
      const storedToken = await AsyncStorage.getItem('auth_token');
      if (storedToken) {
        setToken(storedToken);
        api.defaults.headers.common['Authorization'] = `Bearer ${storedToken}`;
        const response = await api.get('/auth/me');
        const userData = response.data.user;
        const roles = response.data.roles || [];
        const roleNames = roles.map((r: any) => r.name || r);
        const permissions = response.data.permissions || [];
        setUser({ ...userData, roles, role_names: roleNames, permissions });
      }
    } catch {
      await AsyncStorage.removeItem('auth_token');
      delete api.defaults.headers.common['Authorization'];
      setToken(null);
      setUser(null);
    } finally {
      setLoading(false);
    }
  };

  const refreshUser = useCallback(async () => {
    try {
      const response = await api.get('/auth/me');
      const userData = response.data.user;
      const roles = response.data.roles || [];
      const roleNames = roles.map((r: any) => r.name || r);
      const permissions = response.data.permissions || [];
      setUser(prev => prev ? { ...prev, ...userData, roles, role_names: roleNames, permissions } : null);
    } catch {
      // silent fail
    }
  }, []);

  const login = useCallback(async (email: string, password: string) => {
    const response = await api.post('/auth/login', { email, password });
    const { token: newToken, user: userData } = response.data;
    await AsyncStorage.setItem('auth_token', newToken);
    api.defaults.headers.common['Authorization'] = `Bearer ${newToken}`;
    setToken(newToken);

    const meResponse = await api.get('/auth/me');
    const roles = meResponse.data.roles || [];
    const roleNames = roles.map((r: any) => r.name || r);
    const permissions = meResponse.data.permissions || [];

    setUser({ ...userData, ...meResponse.data.user, roles, role_names: roleNames, permissions });
  }, []);

  const logout = useCallback(async () => {
    await AsyncStorage.removeItem('auth_token');
    delete api.defaults.headers.common['Authorization'];
    setToken(null);
    setUser(null);
  }, []);

  const hasPermission = useCallback(
    (key: string) => {
      if (!user) return false;
      if (user.role_names?.some(r => ADMIN_ROLES.includes(r))) return true;
      if (user.permissions && Array.isArray(user.permissions)) {
        return user.permissions.includes(key);
      }
      if (user.roles && Array.isArray(user.roles)) {
        return user.roles.some((role: any) => {
          if (role.permissions && Array.isArray(role.permissions)) {
            return role.permissions.some((p: any) => p.permission_key === key);
          }
          return false;
        });
      }
      return false;
    },
    [user]
  );

  const hasRole = useCallback(
    (...roles: string[]) => {
      if (!user?.role_names) return false;
      return user.role_names.some(r => roles.includes(r));
    },
    [user]
  );

  const isAdmin = user?.role_names?.some(r => ADMIN_ROLES.includes(r)) ?? false;

  return (
    <AuthContext.Provider
      value={{
        user,
        token,
        loading,
        isAuthenticated: !!user,
        isAdmin,
        login,
        logout,
        hasPermission,
        hasRole,
        refreshUser,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}
