package net.siegeln.cameleer.saas.certificate;

import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

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

@RestController
@RequestMapping("/api/vendor/certificates")
@PreAuthorize("hasAuthority('SCOPE_platform:admin')")
public class CertificateController {

    private final CertificateService certificateService;

    public CertificateController(CertificateService certificateService) {
        this.certificateService = certificateService;
    }

    // --- Response types ---

    public record CertificateResponse(
        UUID id, String status, String subject, String issuer,
        Instant notBefore, Instant notAfter, String fingerprint,
        boolean hasCa, boolean selfSigned, Instant activatedAt, Instant archivedAt
    ) {
        public static CertificateResponse from(CertificateEntity e) {
            if (e == null) return null;
            return new CertificateResponse(
                e.getId(), e.getStatus().name(), e.getSubject(), e.getIssuer(),
                e.getNotBefore(), e.getNotAfter(), e.getFingerprint(),
                e.isHasCa(), e.isSelfSigned(), e.getActivatedAt(), e.getArchivedAt()
            );
        }
    }

    public record OverviewResponse(
        CertificateResponse active,
        CertificateResponse staged,
        CertificateResponse archived,
        long staleTenantCount
    ) {}

    public record StageResponse(
        boolean valid,
        List<String> errors,
        CertificateResponse certificate
    ) {}

    // --- Endpoints ---

    @GetMapping
    public ResponseEntity<OverviewResponse> getOverview() {
        var overview = certificateService.getOverview();
        long stale = certificateService.countStaleTenants();
        return ResponseEntity.ok(new OverviewResponse(
            CertificateResponse.from(overview.active()),
            CertificateResponse.from(overview.staged()),
            CertificateResponse.from(overview.archived()),
            stale
        ));
    }

    @PostMapping("/stage")
    public ResponseEntity<StageResponse> stage(
            @RequestParam("cert") MultipartFile certFile,
            @RequestParam("key") MultipartFile keyFile,
            @RequestParam(value = "ca", required = false) MultipartFile caFile,
            @AuthenticationPrincipal Jwt jwt) {
        try {
            byte[] certPem = certFile.getBytes();
            byte[] keyPem = keyFile.getBytes();
            byte[] caPem = caFile != null ? caFile.getBytes() : null;
            UUID actorId = resolveActorId(jwt);

            CertValidationResult result = certificateService.stage(certPem, keyPem, caPem, actorId);

            if (!result.valid()) {
                return ResponseEntity.badRequest().body(
                    new StageResponse(false, result.errors(), null));
            }

            var overview = certificateService.getOverview();
            return ResponseEntity.ok(new StageResponse(
                true, List.of(), CertificateResponse.from(overview.staged())));
        } catch (Exception e) {
            return ResponseEntity.badRequest().body(
                new StageResponse(false, List.of(e.getMessage()), null));
        }
    }

    @PostMapping("/activate")
    public ResponseEntity<Void> activate() {
        certificateService.activate();
        return ResponseEntity.noContent().build();
    }

    @PostMapping("/restore")
    public ResponseEntity<Void> restore() {
        try {
            certificateService.restore();
            return ResponseEntity.noContent().build();
        } catch (IllegalStateException e) {
            return ResponseEntity.badRequest().body(null);
        }
    }

    @DeleteMapping("/staged")
    public ResponseEntity<Void> discardStaged() {
        certificateService.discardStaged();
        return ResponseEntity.noContent().build();
    }

    @GetMapping("/stale-tenants")
    public ResponseEntity<Map<String, Long>> staleTenants() {
        return ResponseEntity.ok(Map.of("count", certificateService.countStaleTenants()));
    }

    private UUID resolveActorId(Jwt jwt) {
        try {
            return UUID.fromString(jwt.getSubject());
        } catch (Exception e) {
            return UUID.nameUUIDFromBytes(jwt.getSubject().getBytes());
        }
    }
}
