package com.flightticket.aspect;

import com.flightticket.dto.auth.AuthenticationResponse;
import com.flightticket.dto.auth.LoginRequest;
import com.flightticket.service.AuditLogService;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * Aspect for logging authentication attempts
 * Requirements: 12.1
 */
@Aspect
@Component
public class AuthenticationLoggingAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(AuthenticationLoggingAspect.class);
    
    private final AuditLogService auditLogService;
    
    public AuthenticationLoggingAspect(AuditLogService auditLogService) {
        this.auditLogService = auditLogService;
    }
    
    /**
     * Pointcut for authentication method
     */
    @Pointcut("execution(* com.flightticket.service.AuthenticationService.authenticate(..))")
    public void authenticateMethod() {}
    
    /**
     * Log successful authentication
     */
    @AfterReturning(pointcut = "authenticateMethod()", returning = "result")
    public void logSuccessfulAuthentication(JoinPoint joinPoint, AuthenticationResponse result) {
        try {
            Object[] args = joinPoint.getArgs();
            if (args.length > 0 && args[0] instanceof LoginRequest) {
                LoginRequest loginRequest = (LoginRequest) args[0];
                String username = loginRequest.getUsername();
                
                HttpServletRequest request = getCurrentRequest();
                String ipAddress = getClientIpAddress(request);
                String userAgent = getUserAgent(request);
                
                auditLogService.logAuthenticationAttempt(
                    username,
                    true,
                    ipAddress,
                    userAgent,
                    null
                );
            }
        } catch (Exception e) {
            logger.error("Error logging successful authentication", e);
        }
    }
    
    /**
     * Log failed authentication
     */
    @AfterThrowing(pointcut = "authenticateMethod()", throwing = "exception")
    public void logFailedAuthentication(JoinPoint joinPoint, Exception exception) {
        try {
            Object[] args = joinPoint.getArgs();
            if (args.length > 0 && args[0] instanceof LoginRequest) {
                LoginRequest loginRequest = (LoginRequest) args[0];
                String username = loginRequest.getUsername();
                
                HttpServletRequest request = getCurrentRequest();
                String ipAddress = getClientIpAddress(request);
                String userAgent = getUserAgent(request);
                
                String failureReason = exception.getMessage();
                
                auditLogService.logAuthenticationAttempt(
                    username,
                    false,
                    ipAddress,
                    userAgent,
                    failureReason
                );
            }
        } catch (Exception e) {
            logger.error("Error logging failed authentication", e);
        }
    }
    
    /**
     * Get current HTTP request
     */
    private HttpServletRequest getCurrentRequest() {
        ServletRequestAttributes attributes = 
            (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return attributes != null ? attributes.getRequest() : null;
    }
    
    /**
     * Extract client IP address from request
     */
    private String getClientIpAddress(HttpServletRequest request) {
        if (request == null) {
            return null;
        }
        
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("X-Real-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        
        // If multiple IPs in X-Forwarded-For, take the first one
        if (ipAddress != null && ipAddress.contains(",")) {
            ipAddress = ipAddress.split(",")[0].trim();
        }
        
        return ipAddress;
    }
    
    /**
     * Extract user agent from request
     */
    private String getUserAgent(HttpServletRequest request) {
        if (request == null) {
            return null;
        }
        return request.getHeader("User-Agent");
    }
}
