package com.zhpb.gdyd_zhpb_zgf.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Umi-OCR HTTP API 客户端
 * 封装了文档识别的完整异步流程
 */
@Service
public class UmiOcrClient {

    private static final Logger logger = LoggerFactory.getLogger(UmiOcrClient.class);

    private final String baseUrl;
    private final RestTemplate restTemplate;
    private final ObjectMapper objectMapper;

    public UmiOcrClient(String baseUrl, RestTemplate restTemplate, ObjectMapper objectMapper) {
        this.baseUrl = baseUrl.replaceAll("/$", "");
        this.restTemplate = restTemplate;
        this.objectMapper = objectMapper;
        logger.info("UmiOcrClient 初始化完成。目标地址: {}", this.baseUrl);
    }

    /**
     * 发送HTTP请求的通用内部方法
     */
    private JsonNode sendRequest(String method, String endpoint, Map<String, Object> data,
                                MultiValueMap<String, Object> formData) {
        String url = baseUrl + endpoint;
        HttpHeaders headers = new HttpHeaders();

        try {
            HttpEntity<?> entity;
            if (formData != null) {
                headers.setContentType(MediaType.MULTIPART_FORM_DATA);
                entity = new HttpEntity<>(formData, headers);
            } else {
                headers.setContentType(MediaType.APPLICATION_JSON);
                String jsonData = objectMapper.writeValueAsString(data != null ? data : Map.of());
                entity = new HttpEntity<>(jsonData, headers);
            }

            ResponseEntity<String> response;
            if ("GET".equalsIgnoreCase(method)) {
                response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
            } else if ("POST".equalsIgnoreCase(method)) {
                response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
            } else {
                throw new IllegalArgumentException("不支持的HTTP方法: " + method);
            }

            if (response.getStatusCode() != HttpStatus.OK) {
                throw new RuntimeException("HTTP请求失败: " + response.getStatusCode());
            }

            String responseBody = response.getBody();
            if (responseBody == null || responseBody.trim().isEmpty()) {
                // 返回空的成功响应
                return objectMapper.createObjectNode()
                    .put("code", 100)
                    .put("data", "Success (No content)");
            }

            return objectMapper.readTree(responseBody);

        } catch (Exception e) {
            logger.error("请求 {} 失败", url, e);
            throw new RuntimeException("请求错误: " + e.getMessage(), e);
        }
    }

    // ==========================================================================
    // 📚 文档识别（PDF等文件）接口封装
    // ==========================================================================

    /**
     * 0. 准备工作：参数查询 (/api/doc/get_options)
     */
    public JsonNode docGetOptions() {
        return sendRequest("GET", "/api/doc/get_options", null, null);
    }

    /**
     * 1. 上传待识别文档 (/api/doc/upload)，返回任务ID
     */
    public String docUpload(String filePath, Map<String, Object> options) throws Exception {
        logger.info("🚀 上传文件: {}", filePath);

        File file = new File(filePath);
        if (!file.exists()) {
            throw new RuntimeException("文件不存在: " + filePath);
        }

        // 清理可能有问题的选项
        Map<String, Object> cleanOptions = new HashMap<>();
        if (options != null) {
            cleanOptions.putAll(options);
            // 移除可能导致问题的页数范围设置，让OCR服务自动处理
            cleanOptions.remove("pageRangeEnd");
            cleanOptions.remove("pageRangeStart");
        }

        MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
        formData.add("json", objectMapper.writeValueAsString(cleanOptions));
        formData.add("file", new org.springframework.core.io.FileSystemResource(file));

        JsonNode response = sendRequest("POST", "/api/doc/upload", null, formData);

        if (response.get("code").asInt() == 100) {
            return response.get("data").asText();
        } else {
            throw new RuntimeException("文件上传失败: " + response.get("data").asText());
        }
    }

    /**
     * 2. 查询任务状态 (/api/doc/result)
     */
    public JsonNode docQueryResult(String taskId, boolean isData, boolean isUnread, String dataFormat) {
        Map<String, Object> requestData = new HashMap<>();
        requestData.put("id", taskId);
        requestData.put("is_data", isData);
        requestData.put("is_unread", isUnread);
        requestData.put("format", dataFormat);

        return sendRequest("POST", "/api/doc/result", requestData, null);
    }

    /**
     * 3. 获取结果下载链接 (/api/doc/download)
     */
    public Map<String, String> docGetDownloadLink(String taskId, List<String> fileTypes, boolean ignoreBlank) {
        Map<String, Object> requestData = new HashMap<>();
        requestData.put("id", taskId);
        requestData.put("file_types", fileTypes);
        requestData.put("ignore_blank", ignoreBlank);

        JsonNode response = sendRequest("POST", "/api/doc/download", requestData, null);

        if (response.get("code").asInt() == 100) {
            Map<String, String> result = new HashMap<>();
            result.put("download_url", baseUrl + response.get("data").asText());
            result.put("file_name", response.get("name").asText());
            return result;
        } else {
            throw new RuntimeException("生成下载链接失败: " + response.get("data").asText());
        }
    }

    /**
     * 5. 任务清理 (/api/doc/clear/<id>)
     */
    public boolean docClearTask(String taskId) {
        JsonNode response = sendRequest("GET", "/api/doc/clear/" + taskId, null, null);

        if (response.get("code").asInt() == 100) {
            logger.info("🧹 任务ID {} 清理成功", taskId);
            return true;
        } else {
            logger.warn("⚠️ 任务ID {} 清理失败或不存在: {}", taskId, response.get("data").asText());
            return false;
        }
    }

    /**
     * 同步执行整个文档OCR流程 (上传 -> 轮询 -> 下载链接 -> 清理)
     */
    public Map<String, Object> runDocOcrSync(String filePath, Map<String, Object> options,
                                           List<String> downloadFileTypes, int interval) throws Exception {
        String taskId = null;
        try {
            // 1. 上传文件，获取任务ID
            taskId = docUpload(filePath, options);
            logger.info("📝 任务启动成功，任务ID: {}", taskId);

            // 2. 轮询任务状态
            logger.info("⏳ 正在轮询任务状态...");
            while (true) {
                JsonNode statusRes = docQueryResult(taskId, false, true, "dict");

                boolean isDone = statusRes.get("is_done").asBoolean(false);
                String state = statusRes.get("state").asText("unknown");
                int processed = statusRes.get("processed_count").asInt(0);
                String total = statusRes.get("pages_count").asText("?");

                logger.info("   - 状态: {} ({}/{} 页已处理)", state.toUpperCase(), processed, total);

                if (isDone) {
                    if ("success".equals(state)) {
                        logger.info("✅ 任务完成！");
                        break;
                    } else {
                        String message = statusRes.get("message").asText("未知错误");
                        throw new RuntimeException("任务执行失败 (State: " + state + "): " + message);
                    }
                }

                Thread.sleep(interval * 1000L);
            }

            // 3. 获取下载链接
            Map<String, String> downloadInfo = docGetDownloadLink(taskId, downloadFileTypes, true);
            logger.info("🔗 下载链接生成成功。文件: {}", downloadInfo.get("file_name"));

            // 4. 获取识别文本（可选步骤，通过查询获取）
            JsonNode textResult = docQueryResult(taskId, true, true, "text");
            String recognizedText = textResult.get("data").asText();

            Map<String, Object> result = new HashMap<>();
            result.put("code", 100);
            result.put("task_id", taskId);
            result.put("download_info", downloadInfo);
            result.put("recognized_text", recognizedText);
            return result;

        } catch (Exception e) {
            throw new RuntimeException("文档识别流程失败: " + e.getMessage(), e);
        } finally {
            // 5. 任务清理
            if (taskId != null) {
                docClearTask(taskId);
            }
        }
    }
}
