package de.cannamanage.service;

import de.cannamanage.domain.entity.Consent;
import de.cannamanage.domain.enums.ConsentType;
import de.cannamanage.service.repository.ConsentRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * Manages DSGVO consent lifecycle: grant, revoke, check.
 */
@Service
public class ConsentService {

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

    private final ConsentRepository consentRepository;

    public ConsentService(ConsentRepository consentRepository) {
        this.consentRepository = consentRepository;
    }

    /**
     * Grant a specific consent type for a user.
     * Creates a new record or re-grants a previously revoked one.
     */
    @Transactional
    public Consent grantConsent(UUID userId, ConsentType type, int version, String ipAddress, String userAgent) {
        Consent consent = consentRepository.findByUserIdAndConsentType(userId, type)
                .orElseGet(() -> {
                    Consent c = new Consent();
                    c.setUserId(userId);
                    c.setConsentType(type);
                    return c;
                });

        consent.setGranted(true);
        consent.setGrantedAt(Instant.now());
        consent.setRevokedAt(null);
        consent.setVersion(version);
        consent.setIpAddress(ipAddress);
        consent.setUserAgent(userAgent);
        consent.setUpdatedAt(Instant.now());

        log.info("Consent granted: userId={}, type={}, version={}", userId, type, version);
        return consentRepository.save(consent);
    }

    /**
     * Revoke a specific consent type for a user.
     */
    @Transactional
    public void revokeConsent(UUID userId, ConsentType type) {
        consentRepository.findByUserIdAndConsentType(userId, type)
                .ifPresent(consent -> {
                    consent.setGranted(false);
                    consent.setRevokedAt(Instant.now());
                    consent.setUpdatedAt(Instant.now());
                    consentRepository.save(consent);
                    log.info("Consent revoked: userId={}, type={}", userId, type);
                });
    }

    /**
     * Revoke all consents for a user (used during account deletion).
     */
    @Transactional
    public void revokeAllConsents(UUID userId) {
        List<Consent> consents = consentRepository.findByUserIdAndGrantedTrue(userId);
        Instant now = Instant.now();
        for (Consent consent : consents) {
            consent.setGranted(false);
            consent.setRevokedAt(now);
            consent.setUpdatedAt(now);
        }
        consentRepository.saveAll(consents);
        log.info("All consents revoked for userId={}", userId);
    }

    /**
     * Check if a user has the required DATA_PROCESSING consent.
     */
    public boolean hasRequiredConsents(UUID userId) {
        return consentRepository.existsByUserIdAndConsentTypeAndGrantedTrue(userId, ConsentType.DATA_PROCESSING);
    }

    /**
     * Get all consent records for a user.
     */
    @Transactional(readOnly = true)
    public List<Consent> getUserConsents(UUID userId) {
        return consentRepository.findByUserId(userId);
    }
}
