package com.gnx.telemedicine.controller;

import com.gnx.telemedicine.dto.audit.HipaaAuditLogResponseDto;
import com.gnx.telemedicine.model.HipaaAuditLog;
import com.gnx.telemedicine.model.enums.ActionType;
import com.gnx.telemedicine.service.HipaaAuditService;
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.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/v3/audit/hipaa")
@RequiredArgsConstructor
@Tag(name = "HIPAA Audit Logs", description = "Endpoints for viewing HIPAA compliance audit logs (Admin only)")
@SecurityRequirement(name = "bearerAuth")
public class HipaaAuditController {
    
    private final HipaaAuditService hipaaAuditService;

    @Operation(
            summary = "Get audit logs by patient ID",
            description = "Retrieve all HIPAA audit logs for a specific patient. Admin only.",
            parameters = @Parameter(name = "patientId", description = "Patient ID", required = true)
    )
    @ApiResponse(
            responseCode = "200",
            description = "List of audit logs retrieved successfully",
            content = @Content(
                    mediaType = "application/json",
                    array = @ArraySchema(schema = @Schema(implementation = HipaaAuditLogResponseDto.class))
            )
    )
    @GetMapping("/patient/{patientId}")
    public ResponseEntity<List<HipaaAuditLogResponseDto>> getAuditLogsByPatientId(
            @PathVariable UUID patientId) {
        List<HipaaAuditLog> logs = hipaaAuditService.getAuditLogsByPatientId(patientId);
        List<HipaaAuditLogResponseDto> response = logs.stream()
                .map(this::toDto)
                .collect(Collectors.toList());
        return ResponseEntity.ok(response);
    }

    @Operation(
            summary = "Get audit logs by patient ID and date range",
            description = "Retrieve HIPAA audit logs for a patient within a date range."
    )
    @GetMapping("/patient/{patientId}/date-range")
    public ResponseEntity<List<HipaaAuditLogResponseDto>> getAuditLogsByPatientIdAndDateRange(
            @PathVariable UUID patientId,
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Instant startDate,
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Instant endDate) {
        List<HipaaAuditLog> logs = hipaaAuditService.getAuditLogsByPatientIdAndDateRange(patientId, startDate, endDate);
        List<HipaaAuditLogResponseDto> response = logs.stream()
                .map(this::toDto)
                .collect(Collectors.toList());
        return ResponseEntity.ok(response);
    }

    @Operation(
            summary = "Get audit logs by user ID",
            description = "Retrieve all HIPAA audit logs for a specific user."
    )
    @GetMapping("/user/{userId}")
    public ResponseEntity<List<HipaaAuditLogResponseDto>> getAuditLogsByUserId(
            @PathVariable UUID userId) {
        List<HipaaAuditLog> logs = hipaaAuditService.getAuditLogsByUserId(userId);
        List<HipaaAuditLogResponseDto> response = logs.stream()
                .map(this::toDto)
                .collect(Collectors.toList());
        return ResponseEntity.ok(response);
    }

    @Operation(
            summary = "Get audit logs by resource",
            description = "Retrieve all HIPAA audit logs for a specific resource."
    )
    @GetMapping("/resource/{resourceType}/{resourceId}")
    public ResponseEntity<List<HipaaAuditLogResponseDto>> getAuditLogsByResource(
            @PathVariable String resourceType,
            @PathVariable UUID resourceId) {
        List<HipaaAuditLog> logs = hipaaAuditService.getAuditLogsByResource(resourceType, resourceId);
        List<HipaaAuditLogResponseDto> response = logs.stream()
                .map(this::toDto)
                .collect(Collectors.toList());
        return ResponseEntity.ok(response);
    }

    @Operation(
            summary = "Get access count for patient",
            description = "Get the number of PHI accesses for a patient since a given date."
    )
    @GetMapping("/patient/{patientId}/access-count")
    public ResponseEntity<Long> getAccessCount(
            @PathVariable UUID patientId,
            @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Instant since) {
        Long count = hipaaAuditService.countAccessesByPatientIdSince(patientId, since);
        return ResponseEntity.ok(count);
    }

    private HipaaAuditLogResponseDto toDto(HipaaAuditLog log) {
        return new HipaaAuditLogResponseDto(
                log.getId(),
                log.getUser().getId(),
                log.getUser().getFirstName() + " " + log.getUser().getLastName(),
                log.getUser().getEmail(),
                log.getActionType(),
                log.getResourceType(),
                log.getResourceId(),
                log.getPatient() != null ? log.getPatient().getId() : null,
                log.getPatient() != null ? 
                    log.getPatient().getUser().getFirstName() + " " + log.getPatient().getUser().getLastName() : null,
                log.getIpAddress(),
                log.getUserAgent(),
                log.getTimestamp(),
                log.getDetails(),
                log.getSuccess(),
                log.getErrorMessage()
        );
    }
}

