package com.gnx.telemedicine.service;

import com.gnx.telemedicine.model.Patient;
import com.gnx.telemedicine.model.PhiAccessLog;
import com.gnx.telemedicine.model.UserModel;
import com.gnx.telemedicine.repository.PatientRepository;
import com.gnx.telemedicine.repository.PhiAccessLogRepository;
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.UUID;

@Service
@RequiredArgsConstructor
@Slf4j
public class PhiAccessLogService {
    
    private final PhiAccessLogRepository phiAccessLogRepository;
    private final UserRepository userRepository;
    private final PatientRepository patientRepository;

    @Transactional
    public void logPhiAccess(String userEmail, UUID patientId, String accessType, List<String> accessedFields, String purpose, HttpServletRequest request) {
        try {
            UserModel user = userRepository.findByEmail(userEmail)
                    .orElseThrow(() -> new RuntimeException("User not found"));

            Patient patient = patientRepository.findById(patientId)
                    .orElseThrow(() -> new IllegalArgumentException("Patient not found"));

            PhiAccessLog accessLog = new PhiAccessLog();
            accessLog.setUser(user);
            accessLog.setPatient(patient);
            accessLog.setAccessType(accessType);
            accessLog.setAccessedFields(accessedFields);
            accessLog.setPurpose(purpose);
            accessLog.setTimestamp(Instant.now());

            // Extract IP address and user agent from request
            if (request != null) {
                String ipAddress = getClientIpAddress(request);
                accessLog.setIpAddress(ipAddress);
                accessLog.setUserAgent(request.getHeader("User-Agent"));
            }

            phiAccessLogRepository.save(accessLog);
        } catch (Exception e) {
            // Log error but don't throw - audit logging should not break the main flow
            log.error("Failed to create PHI access log: {}", e.getMessage(), e);
        }
    }

    @Transactional(readOnly = true)
    public List<PhiAccessLog> getPhiAccessLogsByPatientId(UUID patientId) {
        return phiAccessLogRepository.findByPatientIdOrderByTimestampDesc(patientId);
    }

    @Transactional(readOnly = true)
    public List<PhiAccessLog> getPhiAccessLogsByUserId(UUID userId) {
        return phiAccessLogRepository.findByUserIdOrderByTimestampDesc(userId);
    }

    @Transactional(readOnly = true)
    public List<PhiAccessLog> getPhiAccessLogsByPatientIdAndDateRange(UUID patientId, Instant startDate, Instant endDate) {
        return phiAccessLogRepository.findByPatientIdAndDateRange(patientId, startDate, endDate);
    }

    @Transactional(readOnly = true)
    public Long countDistinctUsersAccessingPatient(UUID patientId, Instant startDate) {
        return phiAccessLogRepository.countDistinctUsersAccessingPatient(patientId, startDate);
    }

    private String getClientIpAddress(HttpServletRequest request) {
        String ipAddress = request.getHeader("X-Forwarded-For");
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.isEmpty() || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
        }
        if (ipAddress != null && ipAddress.contains(",")) {
            ipAddress = ipAddress.split(",")[0].trim();
        }
        return ipAddress;
    }
}

