package com.flightticket.security;

import com.flightticket.model.enums.Role;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Service for checking user permissions and role-based access control
 * Requirements: 1.4, 2.5, 2.6, 2.7, 3.3
 */
@Service
public class PermissionService {
    
    /**
     * Check if the current user has the specified role
     */
    public boolean hasRole(String role) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            return false;
        }
        
        return authentication.getAuthorities().stream()
                .anyMatch(authority -> authority.getAuthority().equals("ROLE_" + role));
    }
    
    /**
     * Check if the current user has any of the specified roles
     */
    public boolean hasAnyRole(String... roles) {
        for (String role : roles) {
            if (hasRole(role)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * Check if the current user has all of the specified roles
     */
    public boolean hasAllRoles(String... roles) {
        for (String role : roles) {
            if (!hasRole(role)) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * Get the current user's agency ID from JWT token
     * Requirements: 3.3
     */
    public String getCurrentUserAgencyId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            return null;
        }
        
        if (authentication.getPrincipal() instanceof Jwt jwt) {
            return jwt.getClaimAsString("agency_id");
        }
        
        return null;
    }
    
    /**
     * Get the current user's ID from JWT token
     */
    public String getCurrentUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            return null;
        }
        
        if (authentication.getPrincipal() instanceof Jwt jwt) {
            return jwt.getSubject();
        }
        
        return null;
    }
    
    /**
     * Get the current user's username from JWT token
     */
    public String getCurrentUsername() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            return null;
        }
        
        if (authentication.getPrincipal() instanceof Jwt jwt) {
            return jwt.getClaimAsString("preferred_username");
        }
        
        return authentication.getName();
    }
    
    /**
     * Get all roles of the current user
     */
    public Set<String> getCurrentUserRoles() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated()) {
            return Set.of();
        }
        
        return authentication.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .map(auth -> auth.replace("ROLE_", ""))
                .collect(Collectors.toSet());
    }
    
    /**
     * Check if the current user is a Super Admin
     * Requirements: 2.2
     */
    public boolean isSuperAdmin() {
        return hasRole(Role.SUPER_ADMIN.name());
    }
    
    /**
     * Check if the current user is an Agency Admin
     * Requirements: 2.3
     */
    public boolean isAgencyAdmin() {
        return hasRole(Role.AGENCY_ADMIN.name());
    }
    
    /**
     * Check if the current user is an HR User
     * Requirements: 2.5
     */
    public boolean isHRUser() {
        return hasRole(Role.HR_USER.name());
    }
    
    /**
     * Check if the current user is a Finance User
     * Requirements: 2.6
     */
    public boolean isFinanceUser() {
        return hasRole(Role.FINANCE_USER.name());
    }
    
    /**
     * Check if the current user is an Agent
     * Requirements: 2.7
     */
    public boolean isAgent() {
        return hasRole(Role.AGENT.name());
    }
    
    /**
     * Check if the current user can access data for the specified agency
     * Super Admin can access all agencies, others can only access their own
     * Requirements: 2.3, 3.3
     */
    public boolean canAccessAgency(String agencyId) {
        if (isSuperAdmin()) {
            return true;
        }
        
        String currentUserAgencyId = getCurrentUserAgencyId();
        return currentUserAgencyId != null && currentUserAgencyId.equals(agencyId);
    }
    
    /**
     * Check if the current user can manage users
     * Super Admin, Agency Admin, and HR User can manage users
     * Requirements: 2.2, 2.3, 2.5
     */
    public boolean canManageUsers() {
        return hasAnyRole(
            Role.SUPER_ADMIN.name(),
            Role.AGENCY_ADMIN.name(),
            Role.HR_USER.name()
        );
    }
    
    /**
     * Check if the current user can manage finances
     * Super Admin and Finance User can manage finances
     * Requirements: 2.6
     */
    public boolean canManageFinances() {
        return hasAnyRole(
            Role.SUPER_ADMIN.name(),
            Role.FINANCE_USER.name()
        );
    }
    
    /**
     * Check if the current user can perform flight operations
     * Super Admin and Agent can perform flight operations
     * Requirements: 2.7
     */
    public boolean canPerformFlightOperations() {
        return hasAnyRole(
            Role.SUPER_ADMIN.name(),
            Role.AGENT.name()
        );
    }
    
    /**
     * Check if the current user can assign the specified role
     * Super Admin can assign any role
     * Agency Admin can only assign roles within their agency (not Super Admin)
     * Requirements: 2.2, 2.3
     */
    public boolean canAssignRole(String role) {
        if (isSuperAdmin()) {
            return true;
        }
        
        if (isAgencyAdmin()) {
            // Agency Admin cannot assign Super Admin role
            return !role.equals(Role.SUPER_ADMIN.name());
        }
        
        return false;
    }
    
    /**
     * Validate that the current user can access the specified agency's data
     * Throws exception if access is denied
     * Requirements: 3.3
     */
    public void validateAgencyAccess(String agencyId) {
        if (!canAccessAgency(agencyId)) {
            throw new SecurityException("Access denied: User cannot access data for agency " + agencyId);
        }
    }
}
