package com.saas.shared.audit;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.saas.shared.core.TenantContext;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@RequiredArgsConstructor
public class AuditService {
    
    private final AuditRepository auditRepository;
    private final ObjectMapper objectMapper;
    
    @Async
    public void log(String userId, String tenantId, String action, String entityType, 
                    String entityId, Object details, HttpServletRequest request) {
        // CRITICAL: Always save audit logs to saas_db, not tenant databases
        String previousTenant = TenantContext.getTenantId();
        
        try {
            // Force saas_db context for audit logging
            TenantContext.setTenantId("saas_db");
            
            String detailsJson = details != null ? objectMapper.writeValueAsString(details) : null;
            String ipAddress = getClientIpAddress(request);
            
            AuditLog auditLog = AuditLog.builder()
                .userId(userId)
                .tenantId(tenantId)
                .action(action)
                .entityType(entityType)
                .entityId(entityId)
                .details(detailsJson)
                .ipAddress(ipAddress)
                .build();
            
            auditRepository.save(auditLog);
            log.info("📋 Audit log saved to saas_db: {} - {} - {} (tenant: {})", 
                     userId, action, entityType, tenantId);
        } catch (JsonProcessingException e) {
            log.error("Failed to serialize audit details", e);
        } catch (Exception e) {
            log.error("Failed to save audit log", e);
        } finally {
            // Restore previous tenant context
            if (previousTenant != null) {
                TenantContext.setTenantId(previousTenant);
            } else {
                TenantContext.clear();
            }
        }
    }
    
    private String getClientIpAddress(HttpServletRequest request) {
        if (request == null) {
            return "UNKNOWN";
        }
        
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty()) {
            return xRealIp;
        }
        
        return request.getRemoteAddr();
    }
}
