package com.lesingle.modules.leai.controller;

import com.lesingle.common.exception.BusinessException;
import com.lesingle.modules.leai.service.ILeaiSyncService;
import com.lesingle.modules.leai.service.ILeaiWebhookEventService;
import com.lesingle.modules.leai.service.LeaiApiClient;
import com.lesingle.modules.leai.util.LeaiUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.*;

/**
 * 乐读派 Webhook 接收控制器
 * 无需认证（由乐读派服务端调用，通过 HMAC 签名验证）
 */
@Slf4j
@Tag(name = "乐读派 Webhook")
@RestController
@RequiredArgsConstructor
public class LeaiWebhookController {

    private final LeaiApiClient leaiApiClient;
    private final ILeaiSyncService leaiSyncService;
    private final ILeaiWebhookEventService webhookEventService;
    private final ObjectMapper objectMapper;

    /**
     * 接收乐读派 Webhook 回调
     * POST /webhook/leai
     * <p>
     * Header:
     *   X-Webhook-Id:        事件唯一 ID
     *   X-Webhook-Event:     事件类型 (work.status_changed / work.progress)
     *   X-Webhook-Timestamp: 毫秒时间戳
     *   X-Webhook-Signature: HMAC-SHA256={hex}
     */
    @PostMapping("/webhook/leai")
    @Operation(summary = "接收乐读派 Webhook 回调")
    public Map<String, String> webhook(
            @RequestBody String rawBody,
            @RequestHeader("X-Webhook-Id") String webhookId,
            @RequestHeader("X-Webhook-Event") String webhookEvent,
            @RequestHeader("X-Webhook-Timestamp") String timestamp,
            @RequestHeader("X-Webhook-Signature") String signature) {

        log.info("[Webhook] 收到事件: event={}, id={}", webhookEvent, webhookId);

        // 1. 时间窗口检查（5分钟，防重放攻击）
        long ts;
        try {
            ts = Long.parseLong(timestamp);
        } catch (NumberFormatException e) {
            log.warn("[Webhook] 时间戳格式错误: {}", timestamp);
            throw new BusinessException(400, "时间戳格式错误");
        }
        if (Math.abs(System.currentTimeMillis() - ts) > 300_000) {
            log.warn("[Webhook] 时间戳已过期: {}", timestamp);
            throw new BusinessException(400, "时间戳已过期");
        }

        // 2. 幂等去重
        if (webhookEventService.existsByEventId(webhookId)) {
            log.info("[Webhook] 重复事件，跳过: {}", webhookId);
            return Collections.singletonMap("status", "duplicate");
        }

        // 3. 验证 HMAC-SHA256 签名
        if (!leaiApiClient.verifyWebhookSignature(webhookId, timestamp, rawBody, signature)) {
            log.warn("[Webhook] 签名验证失败! webhookId={}", webhookId);
            throw new BusinessException(401, "签名验证失败");
        }

        // 4. 解析事件 payload
        Map<String, Object> payload;
        try {
            payload = objectMapper.readValue(rawBody, new TypeReference<Map<String, Object>>() {});
        } catch (Exception e) {
            log.error("[Webhook] payload 解析失败", e);
            throw new BusinessException(400, "payload 解析失败");
        }

        String event = LeaiUtil.toString(payload.get("event"), "");
        @SuppressWarnings("unchecked")
        Map<String, Object> data = (Map<String, Object>) payload.get("data");
        if (data == null) {
            data = new HashMap<>();
        }

        String remoteWorkId = LeaiUtil.toString(data.get("work_id"), null);

        // 5. 按 V4.0 同步规则处理
        boolean syncSuccess = true;
        String errorMsg = null;
        if (remoteWorkId != null && !remoteWorkId.isEmpty()) {
            try {
                leaiSyncService.syncWork(remoteWorkId, data, "Webhook[" + event + "]");
            } catch (Exception e) {
                syncSuccess = false;
                errorMsg = e.getMessage();
                log.error("[Webhook] 同步处理异常: remoteWorkId={}", remoteWorkId, e);
            }
        }

        // 6. 记录事件（标记处理状态，便于定时重试）
        webhookEventService.saveEvent(webhookId, webhookEvent, remoteWorkId, payload, syncSuccess, errorMsg);

        return Collections.singletonMap("status", syncSuccess ? "ok" : "error");
    }
}
