package com.saas.shared.audit;

import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class AuditAspect {
    
    private final AuditService auditService;
    
    @Around("@annotation(auditable)")
    public Object audit(ProceedingJoinPoint joinPoint, Auditable auditable) throws Throwable {
        Object result = joinPoint.proceed();
        
        try {
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
            String userId = auth != null && auth.isAuthenticated() ? auth.getName() : "ANONYMOUS";
            
            ServletRequestAttributes attributes = 
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes != null ? attributes.getRequest() : null;
            
            String entityId = extractEntityId(result);
            
            auditService.log(
                userId,
                null,
                auditable.action(),
                auditable.entityType(),
                entityId,
                result,
                request
            );
        } catch (Exception e) {
            log.error("Failed to create audit log", e);
        }
        
        return result;
    }
    
    private String extractEntityId(Object result) {
        if (result == null) {
            return null;
        }
        
        try {
            if (result.getClass().getMethod("getId") != null) {
                Object id = result.getClass().getMethod("getId").invoke(result);
                return id != null ? id.toString() : null;
            }
        } catch (Exception ignored) {
        }
        
        return null;
    }
}
