package com.cmvr.web.controller.inspection;

import com.cmvr.common.annotation.Anonymous;
import com.cmvr.inspection.domain.dto.alert.AlertEnvelope;
import com.cmvr.inspection.exception.DetectionAlertBadRequestException;
import com.cmvr.inspection.service.IInspectionDetectionAlertService;
import com.fasterxml.jackson.core.JsonProcessingException;
import tools.jackson.databind.ObjectMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * cmvr_edge_ai 检测报警推送入口。
 *
 * 该接口由边缘服务主动调用，使用HTTP状态码表达处理结果，不使用项目通用AjaxResult包装。
 */
@Slf4j
@Anonymous
@RestController
@RequiredArgsConstructor
@Api(tags = "智能巡检--PPE报警接收")
public class InspectionDetectionAlertController
{
    /** 包含Base64图片的JSON请求最大允许20MB，防止异常请求耗尽服务端内存。 */
    private static final int MAX_REQUEST_BYTES = 20 * 1024 * 1024;

    private final IInspectionDetectionAlertService detectionAlertService;
    private final ObjectMapper objectMapper;

    /**
     * 接收PPE违规报警。重复事件视为已处理，仍返回204，避免边缘端持续重试。
     */
    @ApiOperation("接收边缘AI的PPE违规报警")
    @PostMapping(value = "/v1/detection-alerts", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Void> receive(
            @RequestHeader(value = "Idempotency-Key", required = false) String idempotencyKey,
            HttpServletRequest request)
    {
        try
        {
            String requestBody = readRequestBody(request);
            AlertEnvelope envelope = objectMapper.readValue(requestBody, AlertEnvelope.class);
            detectionAlertService.receive(envelope, idempotencyKey);
            return ResponseEntity.noContent().build();
        }
        catch (JsonProcessingException | DetectionAlertBadRequestException ex)
        {
            log.warn("拒绝不合法的PPE报警请求，idempotencyKey={}，原因={}", idempotencyKey, ex.getMessage());
            return ResponseEntity.badRequest().build();
        }
        catch (DuplicateKeyException ex)
        {
            // 预查与插入之间仍可能发生并发，由数据库唯一索引完成最终幂等。
            log.info("忽略并发重复的PPE报警，idempotencyKey={}", idempotencyKey);
            return ResponseEntity.noContent().build();
        }
        catch (IOException ex)
        {
            log.warn("读取PPE报警请求失败，idempotencyKey={}，原因={}", idempotencyKey, ex.getMessage());
            return ResponseEntity.badRequest().build();
        }
        catch (Exception ex)
        {
            log.error("PPE报警处理暂时失败，idempotencyKey={}", idempotencyKey, ex);
            return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).build();
        }
    }

    private String readRequestBody(HttpServletRequest request) throws IOException
    {
        long contentLength = request.getContentLengthLong();
        if (contentLength > MAX_REQUEST_BYTES)
        {
            throw new DetectionAlertBadRequestException("请求体不能超过20MB");
        }

        try (ServletInputStream inputStream = request.getInputStream();
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream(initialCapacity(contentLength)))
        {
            byte[] buffer = new byte[8192];
            int total = 0;
            int length;
            while ((length = inputStream.read(buffer)) != -1)
            {
                total += length;
                if (total > MAX_REQUEST_BYTES)
                {
                    throw new DetectionAlertBadRequestException("请求体不能超过20MB");
                }
                outputStream.write(buffer, 0, length);
            }
            if (total == 0)
            {
                throw new DetectionAlertBadRequestException("请求体不能为空");
            }
            return new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
        }
    }

    private int initialCapacity(long contentLength)
    {
        if (contentLength <= 0 || contentLength > MAX_REQUEST_BYTES)
        {
            return 8192;
        }
        return (int) contentLength;
    }
}
