package com.gnx.telemedicine.controller;

import com.gnx.telemedicine.annotation.LogPhiAccess;
import com.gnx.telemedicine.dto.medical.LabResultRequestDto;
import com.gnx.telemedicine.dto.medical.LabResultResponseDto;
import com.gnx.telemedicine.model.enums.LabResultStatus;
import com.gnx.telemedicine.service.LabResultService;
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.UUID;

@RestController
@RequestMapping("/api/v3/lab-results")
@RequiredArgsConstructor
@Tag(name = "Lab Results", description = "Endpoints for managing laboratory results")
@SecurityRequirement(name = "bearerAuth")
public class LabResultController {
    
    private final LabResultService labResultService;

    @Operation(
            summary = "Get lab results by patient ID",
            description = "Retrieve all lab results for a specific patient.",
            parameters = @Parameter(name = "patientId", description = "Patient ID", required = true)
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "List of lab results retrieved successfully",
                    content = @Content(
                            mediaType = "application/json",
                            array = @ArraySchema(schema = @Schema(implementation = LabResultResponseDto.class))
                    )
            )
    })
    @LogPhiAccess(
            resourceType = "LAB_RESULT",
            patientIdParam = "patientId",
            accessType = "Treatment",
            accessedFields = {"testName", "resultValue", "status", "resultFileUrl"}
    )
    @GetMapping("/patient/{patientId}")
    public ResponseEntity<List<LabResultResponseDto>> getLabResultsByPatientId(
            @PathVariable UUID patientId) {
        return ResponseEntity.ok(labResultService.getLabResultsByPatientId(patientId));
    }

    @Operation(
            summary = "Get lab results by patient ID and status",
            description = "Retrieve lab results filtered by status for a specific patient.",
            parameters = {
                    @Parameter(name = "patientId", description = "Patient ID", required = true),
                    @Parameter(name = "status", description = "Status (NORMAL, ABNORMAL, CRITICAL, PENDING)", required = true)
            }
    )
    @GetMapping("/patient/{patientId}/status/{status}")
    public ResponseEntity<List<LabResultResponseDto>> getLabResultsByPatientIdAndStatus(
            @PathVariable UUID patientId,
            @PathVariable LabResultStatus status) {
        return ResponseEntity.ok(labResultService.getLabResultsByPatientIdAndStatus(patientId, status));
    }

    @Operation(
            summary = "Get abnormal lab results by patient ID",
            description = "Retrieve only abnormal or critical lab results for a patient."
    )
    @GetMapping("/patient/{patientId}/abnormal")
    public ResponseEntity<List<LabResultResponseDto>> getAbnormalLabResultsByPatientId(
            @PathVariable UUID patientId) {
        return ResponseEntity.ok(labResultService.getAbnormalLabResultsByPatientId(patientId));
    }

    @Operation(
            summary = "Get lab results by medical record ID",
            description = "Retrieve all lab results associated with a specific medical record."
    )
    @GetMapping("/medical-record/{medicalRecordId}")
    public ResponseEntity<List<LabResultResponseDto>> getLabResultsByMedicalRecordId(
            @PathVariable UUID medicalRecordId) {
        return ResponseEntity.ok(labResultService.getLabResultsByMedicalRecordId(medicalRecordId));
    }

    @Operation(
            summary = "Create a lab result",
            description = "Create a new lab result. Must be associated with a medical record.",
            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
                    description = "Lab result details",
                    required = true,
                    content = @Content(schema = @Schema(implementation = LabResultRequestDto.class))
            )
    )
    @ApiResponses(value = {
            @ApiResponse(
                    responseCode = "200",
                    description = "Lab result created successfully",
                    content = @Content(schema = @Schema(implementation = LabResultResponseDto.class))
            ),
            @ApiResponse(responseCode = "400", description = "Validation error")
    })
    @PostMapping
    public ResponseEntity<LabResultResponseDto> createLabResult(
            Authentication authentication,
            @RequestBody @Valid LabResultRequestDto requestDto) {
        String userEmail = authentication.getName();
        LabResultResponseDto response = labResultService.createLabResult(userEmail, requestDto);
        return ResponseEntity.ok(response);
    }

    @Operation(
            summary = "Get lab result by ID",
            description = "Retrieve a specific lab result by its ID."
    )
    @LogPhiAccess(
            resourceType = "LAB_RESULT",
            resourceIdParam = "id",
            accessType = "Treatment",
            accessedFields = {"testName", "resultValue", "status", "resultFileUrl"}
    )
    @GetMapping("/{id}")
    public ResponseEntity<LabResultResponseDto> getLabResultById(@PathVariable UUID id) {
        return ResponseEntity.ok(labResultService.getLabResultById(id));
    }

    @Operation(
            summary = "Update a lab result",
            description = "Update an existing lab result."
    )
    @PutMapping("/{id}")
    public ResponseEntity<LabResultResponseDto> updateLabResult(
            Authentication authentication,
            @PathVariable UUID id,
            @RequestBody @Valid LabResultRequestDto requestDto) {
        String userEmail = authentication.getName();
        LabResultResponseDto response = labResultService.updateLabResult(userEmail, id, requestDto);
        return ResponseEntity.ok(response);
    }

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

