package de.cannamanage.api.controller;

import de.cannamanage.domain.entity.Consent;
import de.cannamanage.domain.entity.TenantContext;
import de.cannamanage.domain.entity.User;
import de.cannamanage.domain.enums.ConsentType;
import de.cannamanage.service.ConsentService;
import de.cannamanage.service.repository.UserRepository;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

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

import static org.springframework.http.HttpStatus.NOT_FOUND;

@RestController
@RequestMapping("/api/v1/consent")
@RequiredArgsConstructor
@Tag(name = "Consent", description = "DSGVO consent management")
public class ConsentController {

    private final ConsentService consentService;
    private final UserRepository userRepository;

    @GetMapping
    @Operation(summary = "Get current user's consents")
    public ResponseEntity<List<ConsentResponse>> getConsents(Authentication auth) {
        UUID userId = resolveUserId(auth);
        List<ConsentResponse> consents = consentService.getUserConsents(userId).stream()
                .map(this::toResponse)
                .toList();
        return ResponseEntity.ok(consents);
    }

    @PostMapping
    @Operation(summary = "Grant consent")
    public ResponseEntity<ConsentResponse> grantConsent(
            @RequestBody GrantConsentRequest request,
            Authentication auth,
            HttpServletRequest httpRequest) {
        UUID userId = resolveUserId(auth);
        String ipAddress = httpRequest.getRemoteAddr();
        String userAgent = httpRequest.getHeader("User-Agent");

        Consent consent = consentService.grantConsent(
                userId,
                request.type(),
                request.version() != null ? request.version() : 1,
                ipAddress,
                userAgent
        );
        return ResponseEntity.ok(toResponse(consent));
    }

    @DeleteMapping("/{type}")
    @Operation(summary = "Revoke consent")
    public ResponseEntity<Void> revokeConsent(@PathVariable String type, Authentication auth) {
        UUID userId = resolveUserId(auth);
        ConsentType consentType = ConsentType.valueOf(type);
        consentService.revokeConsent(userId, consentType);
        return ResponseEntity.noContent().build();
    }

    @GetMapping("/check")
    @Operation(summary = "Check if user has required DATA_PROCESSING consent")
    public ResponseEntity<Map<String, Boolean>> checkConsent(Authentication auth) {
        UUID userId = resolveUserId(auth);
        boolean hasConsent = consentService.hasRequiredConsents(userId);
        return ResponseEntity.ok(Map.of("hasDataProcessingConsent", hasConsent));
    }

    private UUID resolveUserId(Authentication auth) {
        // JwtAuthFilter sets the Authentication principal to the userId (the JWT subject),
        // so auth.getName() is the userId UUID — NOT an email. Parse it directly and verify
        // the user exists in the current tenant. (Previously this did findByEmailAndTenantId
        // on auth.getName(), which searched the email column for a UUID → always "User not
        // found" → 404/500 on every consent call.)
        UUID userId;
        try {
            userId = UUID.fromString(auth.getName());
        } catch (IllegalArgumentException e) {
            throw new ResponseStatusException(NOT_FOUND, "User not found");
        }
        if (!userRepository.existsById(userId)) {
            throw new ResponseStatusException(NOT_FOUND, "User not found");
        }
        return userId;
    }

    private ConsentResponse toResponse(Consent consent) {
        return new ConsentResponse(
                consent.getId(),
                consent.getConsentType().name(),
                consent.isGranted(),
                consent.getGrantedAt() != null ? consent.getGrantedAt().toString() : null,
                consent.getRevokedAt() != null ? consent.getRevokedAt().toString() : null,
                consent.getVersion()
        );
    }

    public record GrantConsentRequest(ConsentType type, Integer version) {}
    public record ConsentResponse(UUID id, String type, boolean granted, String grantedAt, String revokedAt, int version) {}
}
