package com.gnx.telemedicine.service;

import com.gnx.telemedicine.dto.audit.BreachNotificationRequestDto;
import com.gnx.telemedicine.dto.audit.BreachNotificationResponseDto;
import com.gnx.telemedicine.model.BreachNotification;
import com.gnx.telemedicine.model.UserModel;
import com.gnx.telemedicine.model.enums.BreachStatus;
import com.gnx.telemedicine.repository.BreachNotificationRepository;
import com.gnx.telemedicine.repository.UserRepository;
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;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class BreachNotificationService {
    
    private final BreachNotificationRepository breachNotificationRepository;
    private final UserRepository userRepository;

    @Transactional(readOnly = true)
    public List<BreachNotificationResponseDto> getAllBreachNotifications() {
        return breachNotificationRepository.findAllByOrderByIncidentDateDesc()
                .stream()
                .map(this::toDto)
                .collect(Collectors.toList());
    }

    @Transactional(readOnly = true)
    public List<BreachNotificationResponseDto> getBreachNotificationsByStatus(BreachStatus status) {
        return breachNotificationRepository.findByStatusOrderByIncidentDateDesc(status)
                .stream()
                .map(this::toDto)
                .collect(Collectors.toList());
    }

    @Transactional
    public BreachNotificationResponseDto createBreachNotification(String userEmail, BreachNotificationRequestDto requestDto) {
        UserModel currentUser = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new RuntimeException("User not found"));

        BreachNotification breach = new BreachNotification();
        breach.setIncidentDate(requestDto.incidentDate());
        breach.setDiscoveryDate(requestDto.discoveryDate());
        breach.setBreachType(requestDto.breachType());
        breach.setAffectedPatientsCount(requestDto.affectedPatientsCount());
        breach.setDescription(requestDto.description());
        breach.setMitigationSteps(requestDto.mitigationSteps());
        breach.setStatus(BreachStatus.INVESTIGATING);
        breach.setCreatedBy(currentUser);
        breach.setCreatedAt(Instant.now());
        breach.setUpdatedAt(Instant.now());

        BreachNotification saved = breachNotificationRepository.save(breach);
        return toDto(saved);
    }

    @Transactional
    public BreachNotificationResponseDto updateBreachStatus(UUID id, BreachStatus status) {
        BreachNotification breach = breachNotificationRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Breach notification not found"));
        
        breach.setStatus(status);
        
        // If resolved or reported, set notified timestamp
        if (status == BreachStatus.RESOLVED || status == BreachStatus.REPORTED) {
            if (breach.getNotifiedAt() == null) {
                breach.setNotifiedAt(Instant.now());
            }
        }
        
        BreachNotification saved = breachNotificationRepository.save(breach);
        return toDto(saved);
    }

    @Transactional(readOnly = true)
    public BreachNotificationResponseDto getBreachNotificationById(UUID id) {
        BreachNotification breach = breachNotificationRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("Breach notification not found"));
        return toDto(breach);
    }

    private BreachNotificationResponseDto toDto(BreachNotification breach) {
        return new BreachNotificationResponseDto(
                breach.getId(),
                breach.getIncidentDate(),
                breach.getDiscoveryDate(),
                breach.getBreachType(),
                breach.getAffectedPatientsCount(),
                breach.getDescription(),
                breach.getMitigationSteps(),
                breach.getNotifiedAt(),
                breach.getStatus(),
                breach.getCreatedBy().getId(),
                breach.getCreatedBy().getFirstName() + " " + breach.getCreatedBy().getLastName(),
                breach.getCreatedAt(),
                breach.getUpdatedAt()
        );
    }
}

