package com.gnx.telemedicine.service;

import com.gnx.telemedicine.model.DataSubjectConsent;
import com.gnx.telemedicine.model.UserModel;
import com.gnx.telemedicine.model.enums.ConsentStatus;
import com.gnx.telemedicine.model.enums.ConsentType;
import com.gnx.telemedicine.repository.DataSubjectConsentRepository;
import com.gnx.telemedicine.repository.UserRepository;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
@RequiredArgsConstructor
@Slf4j
public class GdprConsentService {
    
    private final DataSubjectConsentRepository consentRepository;
    private final UserRepository userRepository;

    @Transactional
    public DataSubjectConsent grantConsent(String userEmail, ConsentType consentType, String consentVersion, 
                                           String consentMethod, HttpServletRequest request) {
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new IllegalArgumentException("User not found"));

        Optional<DataSubjectConsent> existingConsent = consentRepository.findByUserAndConsentType(user, consentType);
        
        DataSubjectConsent consent;
        if (existingConsent.isPresent()) {
            consent = existingConsent.get();
            // Update existing consent
            if (consent.getConsentStatus() == ConsentStatus.WITHDRAWN) {
                consent.setWithdrawnAt(null);
            }
        } else {
            consent = new DataSubjectConsent();
            consent.setUser(user);
            consent.setConsentType(consentType);
        }
        
        consent.setConsentStatus(ConsentStatus.GRANTED);
        consent.setConsentVersion(consentVersion);
        consent.setConsentMethod(consentMethod);
        consent.setGrantedAt(Instant.now());
        
        if (request != null) {
            consent.setIpAddress(getClientIpAddress(request));
            consent.setUserAgent(request.getHeader("User-Agent"));
        }
        
        return consentRepository.save(consent);
    }

    @Transactional
    public DataSubjectConsent withdrawConsent(String userEmail, ConsentType consentType, HttpServletRequest request) {
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new IllegalArgumentException("User not found"));

        DataSubjectConsent consent = consentRepository.findByUserAndConsentType(user, consentType)
                .orElseThrow(() -> new IllegalArgumentException("Consent not found"));

        consent.setConsentStatus(ConsentStatus.WITHDRAWN);
        consent.setWithdrawnAt(Instant.now());
        
        if (request != null) {
            consent.setIpAddress(getClientIpAddress(request));
            consent.setUserAgent(request.getHeader("User-Agent"));
        }

        return consentRepository.save(consent);
    }

    @Transactional(readOnly = true)
    public List<DataSubjectConsent> getUserConsents(String userEmail) {
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new IllegalArgumentException("User not found"));
        
        return consentRepository.findByUser(user);
    }

    @Transactional(readOnly = true)
    public Optional<DataSubjectConsent> getConsent(String userEmail, ConsentType consentType) {
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new IllegalArgumentException("User not found"));
        
        return consentRepository.findByUserAndConsentType(user, consentType);
    }

    @Transactional(readOnly = true)
    public boolean hasConsent(String userEmail, ConsentType consentType) {
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new IllegalArgumentException("User not found"));
        
        return consentRepository.existsByUserAndConsentTypeAndConsentStatus(
                user, consentType, ConsentStatus.GRANTED);
    }

    @Transactional(readOnly = true)
    public List<DataSubjectConsent> getUserConsentsByStatus(String userEmail, ConsentStatus status) {
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new IllegalArgumentException("User not found"));
        
        return consentRepository.findByUserAndConsentStatus(user, status);
    }

    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0].trim();
        }
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty()) {
            return xRealIp;
        }
        return request.getRemoteAddr();
    }
}

