package com.gnx.telemedicine.service;

import com.gnx.telemedicine.dto.prescription.MedicationIntakeLogRequestDto;
import com.gnx.telemedicine.dto.prescription.MedicationIntakeLogResponseDto;
import com.gnx.telemedicine.mappers.MedicationIntakeLogMapper;
import com.gnx.telemedicine.model.MedicationIntakeLog;
import com.gnx.telemedicine.model.Prescription;
import com.gnx.telemedicine.repository.MedicationIntakeLogRepository;
import com.gnx.telemedicine.repository.PrescriptionRepository;
import lombok.RequiredArgsConstructor;
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
public class MedicationIntakeLogService {
    
    private final MedicationIntakeLogRepository medicationIntakeLogRepository;
    private final MedicationIntakeLogMapper medicationIntakeLogMapper;
    private final PrescriptionRepository prescriptionRepository;

    @Transactional(readOnly = true)
    public List<MedicationIntakeLogResponseDto> getLogsByPrescriptionId(UUID prescriptionId) {
        return medicationIntakeLogRepository.findByPrescriptionIdOrderByScheduledTimeDesc(prescriptionId)
                .stream()
                .map(medicationIntakeLogMapper::toMedicationIntakeLogResponseDto)
                .toList();
    }

    @Transactional(readOnly = true)
    public List<MedicationIntakeLogResponseDto> getMissedDoses(UUID prescriptionId) {
        List<MedicationIntakeLog> missedDoses = medicationIntakeLogRepository.findMissedDoses(prescriptionId, Instant.now());
        return missedDoses.stream()
                .map(medicationIntakeLogMapper::toMedicationIntakeLogResponseDto)
                .toList();
    }

    @Transactional
    public MedicationIntakeLogResponseDto createIntakeLog(MedicationIntakeLogRequestDto requestDto) {
        // Validate prescription exists
        Prescription prescription = prescriptionRepository.findById(requestDto.prescriptionId())
                .orElseThrow(() -> new IllegalArgumentException("Prescription not found"));

        // Create intake log
        MedicationIntakeLog log = medicationIntakeLogMapper.toMedicationIntakeLog(requestDto);
        log.setPrescription(prescription);
        log.setScheduledTime(requestDto.scheduledTime());
        
        if (requestDto.taken() != null && requestDto.taken()) {
            log.setTaken(true);
            log.setTakenAt(Instant.now());
        } else {
            log.setTaken(false);
        }
        
        log.setNotes(requestDto.notes());

        MedicationIntakeLog saved = medicationIntakeLogRepository.save(log);
        return medicationIntakeLogMapper.toMedicationIntakeLogResponseDto(saved);
    }

    @Transactional
    public MedicationIntakeLogResponseDto markDoseAsTaken(UUID id) {
        MedicationIntakeLog log = medicationIntakeLogRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Medication intake log not found"));
        
        log.setTaken(true);
        log.setTakenAt(Instant.now());
        
        MedicationIntakeLog saved = medicationIntakeLogRepository.save(log);
        return medicationIntakeLogMapper.toMedicationIntakeLogResponseDto(saved);
    }

    @Transactional(readOnly = true)
    public MedicationIntakeLogResponseDto getIntakeLogById(UUID id) {
        MedicationIntakeLog log = medicationIntakeLogRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Medication intake log not found"));
        return medicationIntakeLogMapper.toMedicationIntakeLogResponseDto(log);
    }

    @Transactional(readOnly = true)
    public Long getAdherenceRate(UUID prescriptionId) {
        Long totalDoses = medicationIntakeLogRepository.countTotalDosesByPrescriptionId(prescriptionId);
        if (totalDoses == 0) {
            return 0L;
        }
        Long takenDoses = medicationIntakeLogRepository.countTakenDosesByPrescriptionId(prescriptionId);
        return (takenDoses * 100) / totalDoses;
    }

    @Transactional
    public void deleteIntakeLog(UUID id) {
        medicationIntakeLogRepository.deleteById(id);
    }
}

