package com.flightticket.aspect;

import com.flightticket.service.AuditLogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Aspect for logging Amadeus API calls
 * Requirements: 12.2
 */
@Aspect
@Component
public class AmadeusApiLoggingAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(AmadeusApiLoggingAspect.class);
    
    private final AuditLogService auditLogService;
    
    public AmadeusApiLoggingAspect(AuditLogService auditLogService) {
        this.auditLogService = auditLogService;
    }
    
    /**
     * Pointcut for all Amadeus API client methods
     */
    @Pointcut("execution(* com.flightticket.client.amadeus.AmadeusClient.*(..))")
    public void amadeusApiMethods() {}
    
    /**
     * Log Amadeus API calls with execution time and result
     */
    @Around("amadeusApiMethods()")
    public Object logAmadeusApiCall(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        
        long startTime = System.currentTimeMillis();
        boolean success = false;
        int responseStatus = 0;
        String errorMessage = null;
        Object result = null;
        
        try {
            result = joinPoint.proceed();
            success = true;
            responseStatus = 200; // Assume success if no exception
            return result;
        } catch (Exception e) {
            success = false;
            responseStatus = 500; // Assume server error
            errorMessage = e.getMessage();
            throw e;
        } finally {
            long executionTime = System.currentTimeMillis() - startTime;
            
            try {
                UUID userId = getCurrentUserId();
                UUID agencyId = getCurrentAgencyId();
                
                Map<String, Object> requestParams = buildRequestParams(methodName, args);
                
                auditLogService.logAmadeusApiCall(
                    userId,
                    agencyId,
                    methodName,
                    requestParams,
                    responseStatus,
                    executionTime,
                    success,
                    errorMessage
                );
            } catch (Exception e) {
                logger.error("Error logging Amadeus API call", e);
            }
        }
    }
    
    /**
     * Get current user ID from security context
     */
    private UUID getCurrentUserId() {
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.getPrincipal() instanceof Jwt) {
                Jwt jwt = (Jwt) authentication.getPrincipal();
                String userId = jwt.getClaimAsString("sub");
                if (userId != null) {
                    return UUID.fromString(userId);
                }
            }
        } catch (Exception e) {
            logger.debug("Could not extract user ID from security context", e);
        }
        return null;
    }
    
    /**
     * Get current agency ID from security context
     */
    private UUID getCurrentAgencyId() {
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication != null && authentication.getPrincipal() instanceof Jwt) {
                Jwt jwt = (Jwt) authentication.getPrincipal();
                String agencyId = jwt.getClaimAsString("agency_id");
                if (agencyId != null) {
                    return UUID.fromString(agencyId);
                }
            }
        } catch (Exception e) {
            logger.debug("Could not extract agency ID from security context", e);
        }
        return null;
    }
    
    /**
     * Build request parameters map from method arguments
     */
    private Map<String, Object> buildRequestParams(String methodName, Object[] args) {
        Map<String, Object> params = new HashMap<>();
        params.put("method", methodName);
        
        if (args != null && args.length > 0) {
            for (int i = 0; i < args.length; i++) {
                if (args[i] != null) {
                    // Store simple representation to avoid serialization issues
                    params.put("arg" + i, args[i].getClass().getSimpleName());
                }
            }
        }
        
        return params;
    }
}
