package de.cannamanage.service;

import de.cannamanage.domain.entity.AuditEvent;
import de.cannamanage.domain.entity.TenantContext;
import de.cannamanage.domain.enums.AuditEventType;
import de.cannamanage.service.repository.AuditEventRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.List;
import java.util.UUID;

/**
 * Immutable audit log service.
 * Events can only be written (log) and read (query/export) — never updated or deleted.
 */
@Service
@Transactional
public class AuditService {

    private static final Logger log = LoggerFactory.getLogger(AuditService.class);

    private final AuditEventRepository auditEventRepository;
    private final PdfReportGenerator pdfReportGenerator;

    public AuditService(AuditEventRepository auditEventRepository, PdfReportGenerator pdfReportGenerator) {
        this.auditEventRepository = auditEventRepository;
        this.pdfReportGenerator = pdfReportGenerator;
    }

    /**
     * Writes an immutable audit event. Once persisted, it cannot be modified or deleted.
     */
    public AuditEvent log(
            AuditEventType eventType,
            String entityType,
            UUID entityId,
            UUID actorId,
            String actorName,
            String actorRole,
            String description,
            String metadata,
            String ipAddress
    ) {
        UUID tenantId = TenantContext.getCurrentTenant();

        AuditEvent event = AuditEvent.builder()
                .eventType(eventType)
                .entityType(entityType)
                .entityId(entityId)
                .actorId(actorId)
                .actorName(actorName)
                .actorRole(actorRole)
                .description(description)
                .metadata(metadata)
                .ipAddress(ipAddress)
                .tenantId(tenantId)
                .build();

        AuditEvent saved = auditEventRepository.save(event);
        log.debug("Audit event logged: {} {} on {}:{}", eventType, actorName, entityType, entityId);
        return saved;
    }

    /**
     * Paginated, filtered query of audit events.
     */
    @Transactional(readOnly = true)
    public Page<AuditEvent> getEvents(
            UUID tenantId,
            int page,
            int size,
            AuditEventType eventType,
            String entityType,
            UUID actorId,
            Instant from,
            Instant to
    ) {
        return auditEventRepository.findFiltered(
                tenantId, eventType, entityType, actorId, from, to,
                PageRequest.of(page, size)
        );
    }

    /**
     * Export audit events as PDF bytes for a given date range.
     */
    @Transactional(readOnly = true)
    public byte[] exportPdf(UUID tenantId, Instant from, Instant to) {
        List<AuditEvent> events = auditEventRepository.findByTenantIdAndTimestampRange(tenantId, from, to);
        return pdfReportGenerator.generateAuditReport(events, from, to);
    }
}
