package com.gnx.telemedicine.controller;

import com.gnx.telemedicine.dto.patient_safety.CriticalResultAcknowledgmentRequestDto;
import com.gnx.telemedicine.dto.patient_safety.CriticalResultResponseDto;
import com.gnx.telemedicine.model.Doctor;
import com.gnx.telemedicine.model.Patient;
import com.gnx.telemedicine.model.UserModel;
import com.gnx.telemedicine.repository.DoctorRepository;
import com.gnx.telemedicine.repository.PatientRepository;
import com.gnx.telemedicine.repository.UserRepository;
import com.gnx.telemedicine.service.CriticalResultManagementService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/v3/critical-results")
@RequiredArgsConstructor
@Tag(name = "Critical Results", description = "Endpoints for managing critical lab results")
@SecurityRequirement(name = "bearerAuth")
public class CriticalResultController {
    
    private final CriticalResultManagementService criticalResultManagementService;
    private final UserRepository userRepository;
    private final DoctorRepository doctorRepository;
    private final PatientRepository patientRepository;
    
    @Operation(summary = "Get critical results for a patient")
    @GetMapping("/patient/{patientId}")
    public ResponseEntity<List<CriticalResultResponseDto>> getCriticalResultsByPatientId(
            Authentication authentication,
            @PathVariable UUID patientId) {
        String userEmail = authentication.getName();
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new RuntimeException("User not found"));
        
        // Check if user is the patient or the patient's treating doctor
        if (user.getRole().name().equals("PATIENT")) {
            Optional<Patient> patientOpt = patientRepository.findByUser(user);
            if (patientOpt.isEmpty()) {
                return ResponseEntity.status(403).build();
            }
            Patient patient = patientOpt.get();
            if (!patient.getId().equals(patientId)) {
                return ResponseEntity.status(403).build(); // Patients can only see their own critical results
            }
            return ResponseEntity.ok(criticalResultManagementService.getCriticalResultsByPatientId(patientId));
        } else if (user.getRole().name().equals("DOCTOR")) {
            Optional<Doctor> doctorOpt = doctorRepository.findByUser(user);
            if (doctorOpt.isEmpty()) {
                return ResponseEntity.status(403).build();
            }
            Doctor doctor = doctorOpt.get();
            // Doctors can only see critical results for their patients
            List<CriticalResultResponseDto> allResults = criticalResultManagementService.getCriticalResultsByPatientId(patientId);
            // Filter to only results where this doctor is the doctor
            List<CriticalResultResponseDto> filtered = allResults.stream()
                    .filter(result -> result.doctorId() != null && result.doctorId().equals(doctor.getId()))
                    .toList();
            return ResponseEntity.ok(filtered);
        }
        
        return ResponseEntity.status(403).build();
    }
    
    @Operation(summary = "Get unacknowledged critical results for a patient")
    @GetMapping("/patient/{patientId}/unacknowledged")
    public ResponseEntity<List<CriticalResultResponseDto>> getUnacknowledgedCriticalResultsByPatientId(
            Authentication authentication,
            @PathVariable UUID patientId) {
        String userEmail = authentication.getName();
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new RuntimeException("User not found"));
        
        // Check if user is the patient or the patient's treating doctor
        if (user.getRole().name().equals("PATIENT")) {
            Optional<Patient> patientOpt = patientRepository.findByUser(user);
            if (patientOpt.isEmpty()) {
                return ResponseEntity.status(403).build();
            }
            Patient patient = patientOpt.get();
            if (!patient.getId().equals(patientId)) {
                return ResponseEntity.status(403).build(); // Patients can only see their own critical results
            }
            return ResponseEntity.ok(criticalResultManagementService.getUnacknowledgedCriticalResultsByPatientId(patientId));
        } else if (user.getRole().name().equals("DOCTOR")) {
            Optional<Doctor> doctorOpt = doctorRepository.findByUser(user);
            if (doctorOpt.isEmpty()) {
                return ResponseEntity.status(403).build();
            }
            Doctor doctor = doctorOpt.get();
            // Doctors can only see critical results for their patients
            List<CriticalResultResponseDto> allResults = criticalResultManagementService.getUnacknowledgedCriticalResultsByPatientId(patientId);
            // Filter to only results where this doctor is the doctor
            List<CriticalResultResponseDto> filtered = allResults.stream()
                    .filter(result -> result.doctorId() != null && result.doctorId().equals(doctor.getId()))
                    .toList();
            return ResponseEntity.ok(filtered);
        }
        
        return ResponseEntity.status(403).build();
    }
    
    @Operation(summary = "Get unacknowledged critical results for a doctor")
    @GetMapping("/doctor/{doctorId}/unacknowledged")
    public ResponseEntity<List<CriticalResultResponseDto>> getUnacknowledgedCriticalResultsByDoctorId(
            Authentication authentication,
            @PathVariable UUID doctorId) {
        String userEmail = authentication.getName();
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new RuntimeException("User not found"));
        
        // Check if user is the doctor
        if (user.getRole().name().equals("DOCTOR")) {
            Optional<Doctor> doctorOpt = doctorRepository.findByUser(user);
            if (doctorOpt.isEmpty()) {
                return ResponseEntity.status(403).build();
            }
            Doctor doctor = doctorOpt.get();
            if (!doctor.getId().equals(doctorId)) {
                return ResponseEntity.status(403).build(); // Doctors can only see their own critical results
            }
            return ResponseEntity.ok(criticalResultManagementService.getUnacknowledgedCriticalResultsByDoctorId(doctorId));
        }
        
        return ResponseEntity.status(403).build();
    }
    
    @Operation(summary = "Get all unacknowledged critical results for the current user")
    @GetMapping("/unacknowledged")
    public ResponseEntity<List<CriticalResultResponseDto>> getAllUnacknowledgedCriticalResults(
            Authentication authentication) {
        String userEmail = authentication.getName();
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new RuntimeException("User not found"));
        
        // Doctors see critical results for their patients only
        if (user.getRole().name().equals("DOCTOR")) {
            Optional<Doctor> doctorOpt = doctorRepository.findByUser(user);
            if (doctorOpt.isEmpty()) {
                return ResponseEntity.status(403).build();
            }
            Doctor doctor = doctorOpt.get();
            return ResponseEntity.ok(criticalResultManagementService.getUnacknowledgedCriticalResultsByDoctorId(doctor.getId()));
        } else if (user.getRole().name().equals("PATIENT")) {
            // Patients see their own critical results
            Optional<Patient> patientOpt = patientRepository.findByUser(user);
            if (patientOpt.isEmpty()) {
                return ResponseEntity.status(403).build();
            }
            Patient patient = patientOpt.get();
            return ResponseEntity.ok(criticalResultManagementService.getUnacknowledgedCriticalResultsByPatientId(patient.getId()));
        }
        
        // Admins can see all results (for now, return all)
        return ResponseEntity.ok(criticalResultManagementService.getAllUnacknowledgedCriticalResults());
    }
    
    @Operation(summary = "Acknowledge a critical result")
    @PostMapping("/{resultId}/acknowledge")
    public ResponseEntity<CriticalResultResponseDto> acknowledgeCriticalResult(
            Authentication authentication,
            @PathVariable UUID resultId,
            @RequestBody @Valid CriticalResultAcknowledgmentRequestDto requestDto) {
        String userEmail = authentication.getName();
        return ResponseEntity.ok(criticalResultManagementService.acknowledgeCriticalResult(userEmail, resultId, requestDto));
    }
    
    @Operation(summary = "Get critical result by ID")
    @GetMapping("/{id}")
    public ResponseEntity<CriticalResultResponseDto> getCriticalResultById(@PathVariable UUID id) {
        return ResponseEntity.ok(criticalResultManagementService.getCriticalResultById(id));
    }
}

