package com.gnx.telemedicine.controller;

import com.gnx.telemedicine.annotation.LogPhiAccess;
import com.gnx.telemedicine.dto.medical.MedicalRecordRequestDto;
import com.gnx.telemedicine.dto.medical.MedicalRecordResponseDto;
import com.gnx.telemedicine.model.Doctor;
import com.gnx.telemedicine.model.Patient;
import com.gnx.telemedicine.model.UserModel;
import com.gnx.telemedicine.model.enums.RecordType;
import com.gnx.telemedicine.repository.DoctorRepository;
import com.gnx.telemedicine.repository.PatientRepository;
import com.gnx.telemedicine.repository.UserRepository;
import com.gnx.telemedicine.service.MedicalRecordService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
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/medical-records")
@RequiredArgsConstructor
@Tag(name = "Medical Records", description = "Endpoints for managing medical records (EHR)")
@SecurityRequirement(name = "bearerAuth")
public class MedicalRecordController {
    
    private final MedicalRecordService medicalRecordService;
    private final UserRepository userRepository;
    private final DoctorRepository doctorRepository;
    private final PatientRepository patientRepository;

    @Operation(
            summary = "Get medical records by patient ID",
            description = "Retrieve all medical records for a specific patient. Requires authentication.",
            parameters = @Parameter(name = "patientId", description = "Patient ID", required = true)
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "List of medical records retrieved successfully",
                    content = @Content(
                            mediaType = "application/json",
                            array = @ArraySchema(schema = @Schema(implementation = MedicalRecordResponseDto.class))
                    )
            ),
            @ApiResponse(responseCode = "401", description = "Unauthorized")
    })
    @LogPhiAccess(
            resourceType = "MEDICAL_RECORD",
            patientIdParam = "patientId",
            accessType = "Treatment",
            accessedFields = {"title", "content", "diagnosisCode", "recordType"}
    )
    @GetMapping("/patient/{patientId}")
    public ResponseEntity<List<MedicalRecordResponseDto>> getMedicalRecordsByPatientId(
            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 records
            }
            return ResponseEntity.ok(medicalRecordService.getMedicalRecordsByPatientId(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 records for their patients
            return ResponseEntity.ok(medicalRecordService.getMedicalRecordsByPatientIdAndDoctorId(patientId, doctor.getId()));
        }
        
        return ResponseEntity.status(403).build();
    }

    @Operation(
            summary = "Get medical records by patient ID and type",
            description = "Retrieve medical records filtered by record type for a specific patient.",
            parameters = {
                    @Parameter(name = "patientId", description = "Patient ID", required = true),
                    @Parameter(name = "recordType", description = "Record type (DIAGNOSIS, LAB_RESULT, etc.)", required = true)
            }
    )
    @GetMapping("/patient/{patientId}/type/{recordType}")
    public ResponseEntity<List<MedicalRecordResponseDto>> getMedicalRecordsByPatientIdAndType(
            @PathVariable UUID patientId,
            @PathVariable RecordType recordType) {
        return ResponseEntity.ok(medicalRecordService.getMedicalRecordsByPatientIdAndType(patientId, recordType));
    }

    @Operation(
            summary = "Get medical records by doctor ID",
            description = "Retrieve all medical records created by a specific doctor."
    )
    @GetMapping("/doctor/{doctorId}")
    public ResponseEntity<List<MedicalRecordResponseDto>> getMedicalRecordsByDoctorId(
            @PathVariable UUID doctorId) {
        return ResponseEntity.ok(medicalRecordService.getMedicalRecordsByDoctorId(doctorId));
    }

    @Operation(
            summary = "Get medical records by appointment ID",
            description = "Retrieve all medical records associated with a specific appointment."
    )
    @GetMapping("/appointment/{appointmentId}")
    public ResponseEntity<List<MedicalRecordResponseDto>> getMedicalRecordsByAppointmentId(
            @PathVariable UUID appointmentId) {
        return ResponseEntity.ok(medicalRecordService.getMedicalRecordsByAppointmentId(appointmentId));
    }

    @Operation(
            summary = "Create a medical record",
            description = "Create a new medical record. Only doctors can create medical records.",
            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "Medical record details",
                    required = true,
                    content = @Content(schema = @Schema(implementation = MedicalRecordRequestDto.class))
            )
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Medical record created successfully",
                    content = @Content(schema = @Schema(implementation = MedicalRecordResponseDto.class))
            ),
            @ApiResponse(responseCode = "400", description = "Validation error"),
            @ApiResponse(responseCode = "403", description = "Forbidden - Only doctors can create medical records")
    })
    @LogPhiAccess(
            resourceType = "MEDICAL_RECORD",
            patientIdParam = "requestDto",
            accessType = "Treatment",
            accessedFields = {"title", "content", "diagnosisCode", "recordType"}
    )
    @PostMapping
    public ResponseEntity<MedicalRecordResponseDto> createMedicalRecord(
            Authentication authentication,
            @RequestBody @Valid MedicalRecordRequestDto requestDto) {
        String userEmail = authentication.getName();
        MedicalRecordResponseDto response = medicalRecordService.createMedicalRecord(userEmail, requestDto);
        return ResponseEntity.ok(response);
    }

    @Operation(
            summary = "Get medical record by ID",
            description = "Retrieve a specific medical record by its ID."
    )
    @LogPhiAccess(
            resourceType = "MEDICAL_RECORD",
            resourceIdParam = "id",
            accessType = "Treatment",
            accessedFields = {"title", "content", "diagnosisCode", "recordType"}
    )
    @GetMapping("/{id}")
    public ResponseEntity<MedicalRecordResponseDto> getMedicalRecordById(
            Authentication authentication,
            @PathVariable UUID id) {
        String userEmail = authentication.getName();
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new RuntimeException("User not found"));
        
        MedicalRecordResponseDto record = medicalRecordService.getMedicalRecordById(id);
        
        // Check if user is the patient or the treating doctor
        if (user.getRole().name().equals("PATIENT")) {
            Optional<Patient> patientOpt = patientRepository.findByUser(user);
            if (patientOpt.isEmpty() || !patientOpt.get().getId().equals(record.patientId())) {
                return ResponseEntity.status(403).build();
            }
        } else if (user.getRole().name().equals("DOCTOR")) {
            Optional<Doctor> doctorOpt = doctorRepository.findByUser(user);
            if (doctorOpt.isEmpty() || !doctorOpt.get().getId().equals(record.doctorId())) {
                return ResponseEntity.status(403).build();
            }
        } else {
            return ResponseEntity.status(403).build();
        }
        
        return ResponseEntity.ok(record);
    }

    @Operation(
            summary = "Update a medical record",
            description = "Update an existing medical record."
    )
    @PutMapping("/{id}")
    public ResponseEntity<MedicalRecordResponseDto> updateMedicalRecord(
            Authentication authentication,
            @PathVariable UUID id,
            @RequestBody @Valid MedicalRecordRequestDto requestDto) {
        String userEmail = authentication.getName();
        MedicalRecordResponseDto response = medicalRecordService.updateMedicalRecord(userEmail, id, requestDto);
        return ResponseEntity.ok(response);
    }

    @Operation(
            summary = "Delete a medical record",
            description = "Delete a medical record by ID."
    )
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteMedicalRecord(@PathVariable UUID id) {
        medicalRecordService.deleteMedicalRecord(id);
        return ResponseEntity.noContent().build();
    }
}

