package com.gnx.telemedicine.controller;

import com.gnx.telemedicine.annotation.LogPhiAccess;
import com.gnx.telemedicine.dto.prescription.PrescriptionRequestDto;
import com.gnx.telemedicine.dto.prescription.PrescriptionResponseDto;
import com.gnx.telemedicine.model.Doctor;
import com.gnx.telemedicine.model.Patient;
import com.gnx.telemedicine.model.Prescription;
import com.gnx.telemedicine.model.UserModel;
import com.gnx.telemedicine.model.enums.PrescriptionStatus;
import com.gnx.telemedicine.repository.DoctorRepository;
import com.gnx.telemedicine.repository.PatientRepository;
import com.gnx.telemedicine.repository.UserRepository;
import com.gnx.telemedicine.service.PrescriptionService;
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/prescriptions")
@RequiredArgsConstructor
@Tag(name = "Prescriptions", description = "Endpoints for managing prescriptions")
@SecurityRequirement(name = "bearerAuth")
public class PrescriptionController {
    
    private final PrescriptionService prescriptionService;
    private final UserRepository userRepository;
    private final DoctorRepository doctorRepository;
    private final PatientRepository patientRepository;

    @Operation(
            summary = "Get prescriptions by patient ID",
            description = "Retrieve all prescriptions for a specific patient.",
            parameters = @Parameter(name = "patientId", description = "Patient ID", required = true)
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "List of prescriptions retrieved successfully",
                    content = @Content(
                            mediaType = "application/json",
                            array = @ArraySchema(schema = @Schema(implementation = PrescriptionResponseDto.class))
                    )
            )
    })
    @LogPhiAccess(
            resourceType = "PRESCRIPTION",
            patientIdParam = "patientId",
            accessType = "Treatment",
            accessedFields = {"medicationName", "dosage", "frequency", "instructions"}
    )
    @GetMapping("/patient/{patientId}")
    public ResponseEntity<List<PrescriptionResponseDto>> getPrescriptionsByPatientId(
            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 prescriptions
            }
            return ResponseEntity.ok(prescriptionService.getPrescriptionsByPatientId(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 prescriptions for their patients
            return ResponseEntity.ok(prescriptionService.getPrescriptionsByPatientIdAndDoctorId(patientId, doctor.getId()));
        }
        
        return ResponseEntity.status(403).build();
    }

    @Operation(
            summary = "Get active prescriptions by patient ID",
            description = "Retrieve only active prescriptions for a patient."
    )
    @GetMapping("/patient/{patientId}/active")
    public ResponseEntity<List<PrescriptionResponseDto>> getActivePrescriptionsByPatientId(
            @PathVariable UUID patientId) {
        return ResponseEntity.ok(prescriptionService.getActivePrescriptionsByPatientId(patientId));
    }

    @Operation(
            summary = "Get prescriptions by patient ID and status",
            description = "Retrieve prescriptions filtered by status for a specific patient."
    )
    @GetMapping("/patient/{patientId}/status/{status}")
    public ResponseEntity<List<PrescriptionResponseDto>> getPrescriptionsByPatientIdAndStatus(
            @PathVariable UUID patientId,
            @PathVariable PrescriptionStatus status) {
        return ResponseEntity.ok(prescriptionService.getPrescriptionsByPatientIdAndStatus(patientId, status));
    }

    @Operation(
            summary = "Get prescriptions by doctor ID",
            description = "Retrieve all prescriptions created by a specific doctor."
    )
    @GetMapping("/doctor/{doctorId}")
    public ResponseEntity<List<PrescriptionResponseDto>> getPrescriptionsByDoctorId(
            @PathVariable UUID doctorId) {
        return ResponseEntity.ok(prescriptionService.getPrescriptionsByDoctorId(doctorId));
    }

    @Operation(
            summary = "Get prescriptions by appointment ID",
            description = "Retrieve all prescriptions associated with a specific appointment."
    )
    @GetMapping("/appointment/{appointmentId}")
    public ResponseEntity<List<PrescriptionResponseDto>> getPrescriptionsByAppointmentId(
            @PathVariable UUID appointmentId) {
        return ResponseEntity.ok(prescriptionService.getPrescriptionsByAppointmentId(appointmentId));
    }

    @Operation(
            summary = "Get prescription by prescription number",
            description = "Retrieve a prescription by its unique prescription number."
    )
    @GetMapping("/number/{prescriptionNumber}")
    public ResponseEntity<PrescriptionResponseDto> getPrescriptionByNumber(
            @PathVariable String prescriptionNumber) {
        return ResponseEntity.ok(prescriptionService.getPrescriptionByNumber(prescriptionNumber));
    }

    @Operation(
            summary = "Create a prescription",
            description = "Create a new prescription. Only doctors can create prescriptions. A unique prescription number is automatically generated.",
            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "Prescription details",
                    required = true,
                    content = @Content(schema = @Schema(implementation = PrescriptionRequestDto.class))
            )
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Prescription created successfully",
                    content = @Content(schema = @Schema(implementation = PrescriptionResponseDto.class))
            ),
            @ApiResponse(responseCode = "400", description = "Validation error"),
            @ApiResponse(responseCode = "403", description = "Forbidden - Only doctors can create prescriptions")
    })
    @LogPhiAccess(
            resourceType = "PRESCRIPTION",
            patientIdParam = "requestDto",
            accessType = "Treatment",
            accessedFields = {"medicationName", "dosage", "frequency", "instructions"}
    )
    @PostMapping
    public ResponseEntity<PrescriptionResponseDto> createPrescription(
            Authentication authentication,
            @RequestBody @Valid PrescriptionRequestDto requestDto) {
        String userEmail = authentication.getName();
        PrescriptionResponseDto response = prescriptionService.createPrescription(userEmail, requestDto);
        return ResponseEntity.ok(response);
    }

    @Operation(
            summary = "Get prescription by ID",
            description = "Retrieve a specific prescription by its ID."
    )
    @LogPhiAccess(
            resourceType = "PRESCRIPTION",
            resourceIdParam = "id",
            accessType = "Treatment",
            accessedFields = {"medicationName", "dosage", "frequency", "instructions"}
    )
    @GetMapping("/{id}")
    public ResponseEntity<PrescriptionResponseDto> getPrescriptionById(
            Authentication authentication,
            @PathVariable UUID id) {
        String userEmail = authentication.getName();
        UserModel user = userRepository.findByEmail(userEmail)
                .orElseThrow(() -> new RuntimeException("User not found"));
        
        PrescriptionResponseDto prescription = prescriptionService.getPrescriptionById(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(prescription.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(prescription.doctorId())) {
                return ResponseEntity.status(403).build();
            }
        } else {
            return ResponseEntity.status(403).build();
        }
        
        return ResponseEntity.ok(prescription);
    }

    @Operation(
            summary = "Update prescription status",
            description = "Update the status of a prescription (ACTIVE, COMPLETED, CANCELLED, DISCONTINUED)."
    )
    @PatchMapping("/{id}/status")
    public ResponseEntity<PrescriptionResponseDto> updatePrescriptionStatus(
            Authentication authentication,
            @PathVariable UUID id,
            @RequestParam PrescriptionStatus status) {
        String userEmail = authentication.getName();
        PrescriptionResponseDto response = prescriptionService.updatePrescriptionStatus(userEmail, id, status);
        return ResponseEntity.ok(response);
    }

    @Operation(
            summary = "Mark e-prescription as sent",
            description = "Mark that an e-prescription has been sent to the pharmacy."
    )
    @PatchMapping("/{id}/mark-sent")
    public ResponseEntity<PrescriptionResponseDto> markEPrescriptionSent(
            Authentication authentication,
            @PathVariable UUID id) {
        String userEmail = authentication.getName();
        PrescriptionResponseDto response = prescriptionService.markEPrescriptionSent(userEmail, id);
        return ResponseEntity.ok(response);
    }

    @Operation(
            summary = "Update a prescription",
            description = "Update an existing prescription."
    )
    @PutMapping("/{id}")
    public ResponseEntity<PrescriptionResponseDto> updatePrescription(
            Authentication authentication,
            @PathVariable UUID id,
            @RequestBody @Valid PrescriptionRequestDto requestDto) {
        String userEmail = authentication.getName();
        PrescriptionResponseDto response = prescriptionService.updatePrescription(userEmail, id, requestDto);
        return ResponseEntity.ok(response);
    }

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

