package de.cannamanage.api.controller;

import de.cannamanage.domain.entity.AuditEvent;
import de.cannamanage.domain.entity.TenantContext;
import de.cannamanage.domain.enums.AuditEventType;
import de.cannamanage.service.AuditService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.UUID;

@RestController
@RequestMapping("/api/v1/audit")
@RequiredArgsConstructor
@Tag(name = "Audit", description = "Immutable audit log (KCanG compliance, 10-year retention)")
public class AuditController {

    private final AuditService auditService;

    @GetMapping
    @Operation(summary = "Get paginated audit log",
            description = "Returns audit events with optional filters. Admin only.")
    @PreAuthorize("hasRole('ADMIN') or @staffPermissions.has(authentication, T(de.cannamanage.domain.enums.StaffPermission).VIEW_COMPLIANCE_REPORT)")
    public ResponseEntity<Page<AuditEventResponse>> getAuditLog(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(required = false) AuditEventType eventType,
            @RequestParam(required = false) String entityType,
            @RequestParam(required = false) UUID actorId,
            @RequestParam(required = false) Instant from,
            @RequestParam(required = false) Instant to
    ) {
        UUID tenantId = TenantContext.getCurrentTenant();
        Page<AuditEvent> events = auditService.getEvents(
                tenantId, page, size, eventType, entityType, actorId, from, to
        );
        Page<AuditEventResponse> response = events.map(AuditEventResponse::from);
        return ResponseEntity.ok(response);
    }

    @GetMapping("/export")
    @Operation(summary = "Export audit log as PDF",
            description = "Generates a PDF audit report for the specified date range. Admin only.")
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<byte[]> exportAuditPdf(
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to
    ) {
        UUID tenantId = TenantContext.getCurrentTenant();
        Instant fromInstant = from.atStartOfDay(ZoneId.of("Europe/Berlin")).toInstant();
        Instant toInstant = to.plusDays(1).atStartOfDay(ZoneId.of("Europe/Berlin")).toInstant();

        byte[] pdf = auditService.exportPdf(tenantId, fromInstant, toInstant);

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION,
                        "attachment; filename=\"audit-log-" + from + "-to-" + to + ".pdf\"")
                .contentType(MediaType.APPLICATION_PDF)
                .body(pdf);
    }

    /**
     * Response DTO for audit events (read-only projection).
     */
    public record AuditEventResponse(
            UUID id,
            String eventType,
            String entityType,
            UUID entityId,
            UUID actorId,
            String actorName,
            String actorRole,
            String description,
            String metadata,
            String ipAddress,
            Instant timestamp
    ) {
        public static AuditEventResponse from(AuditEvent event) {
            return new AuditEventResponse(
                    event.getId(),
                    event.getEventType().name(),
                    event.getEntityType(),
                    event.getEntityId(),
                    event.getActorId(),
                    event.getActorName(),
                    event.getActorRole(),
                    event.getDescription(),
                    event.getMetadata(),
                    event.getIpAddress(),
                    event.getTimestamp()
            );
        }
    }
}
