package com.yanzhu.module.ai.framework.ai.core.model.xinghuo.api;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HmacAlgorithm;
import com.yanzhu.framework.common.exception.ServiceException;
import com.yanzhu.framework.common.util.json.JsonUtils;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;

import static cn.hutool.core.util.StrUtil.utf8Bytes;
import static cn.hutool.core.util.StrUtil.utf8Str;
import static org.springframework.util.StringUtils.hasText;

/**
 * 讯飞星火 PPT 生成 API
 *
 * @author 研筑科技
 */
@Slf4j
public class XunFeiPptApi {

    private static final String BASE_URL = "https://api.xf-yun.com/v2/ppt";
    private static final String HEADER_APP_ID = "app_id";
    private static final String HEADER_DATE = "date";
    private static final String HEADER_AUTH = "authorization";

    private final String appId;
    private final String apiKey;
    private final String apiSecret;

    private final RestTemplate restTemplate;

    public XunFeiPptApi(String appId, String apiKey, String apiSecret) {
        this.appId = appId;
        this.apiKey = apiKey;
        this.apiSecret = apiSecret;

        this.restTemplate = new RestTemplate();
    }

    /**
     * 签名信息
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private static class SignatureInfo {
        private String timestamp;
        private String signature;
    }

    private SignatureInfo getSignature() {
        long timestamp = System.currentTimeMillis() / 1000;
        String dateTime = ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault()).format(DateTimeFormatter.RFC_1123_DATE_TIME);

        String signatureOrigin = "host: api.xf-yun.com\n" +
                "date: " + dateTime + "\n" +
                "POST /v2/ppt HTTP/1.1";

        byte[] signatureBytes = SecureUtil.hmac(HmacAlgorithm.HmacSHA256, apiSecret.getBytes(StandardCharsets.UTF_8))
                .digest(signatureOrigin.getBytes(StandardCharsets.UTF_8));

        String signature = utf8Str(signatureBytes);

        return new SignatureInfo(String.valueOf(timestamp), signature);
    }

    /**
     * 生成 PPT
     *
     * @param query 生成要求
     * @return 生成结果
     */
    public CreateResponse create(String query) {
        Assert.notNull(query, "生成要求不能为空");

        CreatePptRequest request = CreatePptRequest.builder()
                .query(query)
                .build();

        return create(request);
    }

    /**
     * 生成 PPT
     *
     * @param file 上传文件
     * @return 生成结果
     */
    public CreateResponse create(MultipartFile file) {
        Assert.notNull(file, "上传文件不能为空");

        CreatePptRequest request = CreatePptRequest.builder()
                .file(file)
                .build();

        return create(request);
    }

    /**
     * 生成 PPT
     *
     * @param request 请求体
     * @return 生成结果
     */
    public CreateResponse create(CreatePptRequest request) {
        Assert.notNull(request, "请求体不能为空");

        MultiValueMap<String, Object> formData = buildCreatePptFormData(request);
        
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        headers.add(HEADER_APP_ID, appId);
        
        // 添加认证头
        SignatureInfo signature = getSignature();
        headers.add(HEADER_DATE, signature.timestamp);
        headers.add(HEADER_AUTH, signature.signature);
        
        HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(formData, headers);
        
        try {
            ResponseEntity<CreateResponse> response = restTemplate.exchange(
                    BASE_URL + "/create",
                    HttpMethod.POST,
                    entity,
                    CreateResponse.class
            );
            
            if (response.getStatusCode().series() != HttpStatus.Series.SUCCESSFUL) {
                log.error("调用讯飞 PPT API 异常，参数：{}，状态码：{}，响应：{}", JsonUtils.toJsonString(request), response.getStatusCode(), response.getBody());
                throw new ServiceException(500, "调用讯飞 PPT API 异常：" + (response.getBody() != null ? response.getBody().desc : "未知错误"));
            }
            
            return response.getBody();
        } catch (Exception e) {
            if (e instanceof ServiceException || e instanceof IllegalStateException) {
                throw e;
            }
            log.error("调用讯飞 PPT API 异常，参数：{}", JsonUtils.toJsonString(request), e);
            throw new ServiceException(500, "调用讯飞 PPT API 异常：" + e.getMessage());
        }
    }

    /**
     * 通过大纲生成 PPT
     *
     * @param outlineSid 大纲ID
     * @return 生成结果
     */
    public CreateResponse createByOutline(String outlineSid) {
        Assert.notNull(outlineSid, "大纲ID不能为空");

        CreatePptByOutlineRequest request = CreatePptByOutlineRequest.builder()
                .outlineSid(outlineSid)
                .build();

        return createByOutline(request);
    }

    /**
     * 通过大纲生成 PPT
     *
     * @param request 请求体
     * @return 生成结果
     */
    public CreateResponse createByOutline(CreatePptByOutlineRequest request) {
        Assert.notNull(request, "请求体不能为空");
        
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add(HEADER_APP_ID, appId);
        
        // 添加认证头
        SignatureInfo signature = getSignature();
        headers.add(HEADER_DATE, signature.timestamp);
        headers.add(HEADER_AUTH, signature.signature);
        
        HttpEntity<CreatePptByOutlineRequest> entity = new HttpEntity<>(request, headers);
        
        try {
            ResponseEntity<CreateResponse> response = restTemplate.exchange(
                    BASE_URL + "/createByOutline",
                    HttpMethod.POST,
                    entity,
                    CreateResponse.class
            );
            
            if (response.getStatusCode().series() != HttpStatus.Series.SUCCESSFUL) {
                log.error("调用讯飞 PPT API 异常，参数：{}，状态码：{}，响应：{}", JsonUtils.toJsonString(request), response.getStatusCode(), response.getBody());
                throw new ServiceException(500, "调用讯飞 PPT API 异常：" + (response.getBody() != null ? response.getBody().desc : "未知错误"));
            }
            
            return response.getBody();
        } catch (Exception e) {
            if (e instanceof ServiceException || e instanceof IllegalStateException) {
                throw e;
            }
            log.error("调用讯飞 PPT API 异常，参数：{}", JsonUtils.toJsonString(request), e);
            throw new ServiceException(500, "调用讯飞 PPT API 异常：" + e.getMessage());
        }
    }

    /**
     * 查询模板
     *
     * @return 模板列表
     */
    public TemplatePageResponse getTemplates() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.add(HEADER_APP_ID, appId);
        
        // 添加认证头
        SignatureInfo signature = getSignature();
        headers.add(HEADER_DATE, signature.timestamp);
        headers.add(HEADER_AUTH, signature.signature);
        
        HttpEntity<String> entity = new HttpEntity<>(headers);
        
        try {
            ResponseEntity<TemplatePageResponse> response = restTemplate.exchange(
                    BASE_URL + "/templates",
                    HttpMethod.GET,
                    entity,
                    TemplatePageResponse.class
            );
            
            if (response.getStatusCode().series() != HttpStatus.Series.SUCCESSFUL) {
                log.error("调用讯飞 PPT API 异常，参数：{}，状态码：{}，响应：{}", "查询模板", response.getStatusCode(), response.getBody());
                throw new ServiceException(500, "调用讯飞 PPT API 异常：" + (response.getBody() != null ? response.getBody().desc : "未知错误"));
            }
            
            return response.getBody();
        } catch (Exception e) {
            if (e instanceof ServiceException || e instanceof IllegalStateException) {
                throw e;
            }
            log.error("调用讯飞 PPT API 异常，参数：{}", "查询模板", e);
            throw new ServiceException(500, "调用讯飞 PPT API 异常：" + e.getMessage());
        }
    }

    /**
     * 构建创建 PPT 的表单数据
     *
     * @param request 请求参数
     * @return 表单数据
     */
    private MultiValueMap<String, Object> buildCreatePptFormData(CreatePptRequest request) {
        MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();

        if (request.getFile() != null) {
            try {
                formData.add("file", new ByteArrayResource(request.getFile().getBytes()) {
                    @Override
                    public String getFilename() {
                        return request.getFile().getOriginalFilename();
                    }
                });
            } catch (Exception e) {
                throw new ServiceException(500, "读取上传文件异常：" + e.getMessage());
            }
        }

        Map<String, Object> param = new HashMap<>();
        addIfPresent(param, "query", request.getQuery());
        addIfPresent(param, "fileUrl", request.getFileUrl());
        addIfPresent(param, "fileName", request.getFileName());
        addIfPresent(param, "templateId", request.getTemplateId());
        addIfPresent(param, "businessId", request.getBusinessId());
        addIfPresent(param, "author", request.getAuthor());
        addIfPresent(param, "isCardNote", request.getIsCardNote());
        addIfPresent(param, "search", request.getSearch());
        addIfPresent(param, "language", request.getLanguage());
        addIfPresent(param, "isFigure", request.getIsFigure());
        addIfPresent(param, "aiImage", request.getAiImage());

        param.forEach(formData::add);
        return formData;
    }

    public static <K, V> void addIfPresent(Map<K, V> map, K key, V value) {
        if (ObjUtil.isNull(key) || ObjUtil.isNull(map)) {
            return;
        }

        boolean isPresent = false;
        if (ObjUtil.isNotNull(value)) {
            if (value instanceof String) {
                // 字符串：需要有实际内容
                isPresent = hasText((String) value);
            } else {
                // 其他类型：非 null 即视为存在
                isPresent = true;
            }
        }

        if (isPresent) {
            map.put(key, value);
        }
    }

    /**
     * 模板列表响应
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class TemplatePageResponse {
        private boolean flag;
        private int code;
        private String desc;
        private Integer count;
        private TemplatePageData data;
    }

    /**
     * 模板列表数据
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class TemplatePageData {
        private String total;
        private List<TemplateInfo> records;
        private Integer pageNum;
    }

    /**
     * 模板信息
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class TemplateInfo {
        private String templateIndexId;
        private Integer pageCount;
        private String type;
        private String color;
        private String industry;
        private String style;
        private String detailImage;
    }

    /**
     * 创建响应
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class CreateResponse {
        private boolean flag;
        private int code;
        private String desc;
        private Integer count;
        private CreateResponseData data;
    }

    /**
     * 创建响应数据
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class CreateResponseData {
        private String sid;
        private String coverImgSrc;
        private String title;
        private String subTitle;
        private OutlineData outline;
    }

    /**
     * 大纲数据结构
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class OutlineData {
        private String title;
        private String subTitle;
        private List<Chapter> chapters;

        /**
         * 章节结构
         */
        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @JsonInclude(JsonInclude.Include.NON_NULL)
        public static class Chapter {
            private String chapterTitle;
            private List<ChapterContent> chapterContents;

            /**
             * 章节内容
             */
            @Data
            @NoArgsConstructor
            @AllArgsConstructor
            @JsonInclude(JsonInclude.Include.NON_NULL)
            public static class ChapterContent {
                private String chapterTitle;
            }
        }

        /**
         * 将大纲对象转换为JSON字符串
         *
         * @return 大纲JSON字符串
         */
        public String toJsonString() {
            return JsonUtils.toJsonString(this);
        }
    }

    /**
     * 进度响应
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class ProgressResponse {
        private int code;
        private String desc;
        private ProgressResponseData data;
    }

    /**
     * 进度响应数据
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class ProgressResponseData {
        private int process;
        private String pptId;
        private String pptUrl;
        private String pptStatus;
        private String aiImageStatus;
        private String cardNoteStatus;
        private String errMsg;
        private Integer totalPages;
        private Integer donePages;

        /**
         * 是否全部完成
         *
         * @return 是否全部完成
         */
        public boolean isAllDone() {
            return "done".equals(pptStatus)
                    && ("done".equals(aiImageStatus) || aiImageStatus == null)
                    && ("done".equals(cardNoteStatus) || cardNoteStatus == null);
        }

        /**
         * 是否失败
         *
         * @return 是否失败
         */
        public boolean isFailed() {
            return "build_failed".equals(pptStatus);
        }

        /**
         * 获取进度百分比
         *
         * @return 进度百分比
         */
        public int getProgressPercent() {
            if (totalPages == null || totalPages == 0 || donePages == null) {
                return process; // 兼容旧版返回
            }
            return (int) (donePages * 100.0 / totalPages);
        }
    }

    /**
     * 通过大纲创建 PPT 请求参数
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Builder
    public static class CreatePptByOutlineRequest {
        private String query;                // 用户生成PPT要求（最多8000字）
        private String outlineSid;           // 已生成大纲后，响应返回的请求大纲唯一id
        private OutlineData outline;         // 大纲内容
        private String templateId;           // 模板ID
        private String businessId;           // 业务ID（非必传）
        private String author;               // PPT作者名
        private Boolean isCardNote;          // 是否生成PPT演讲备注
        private Boolean search;              // 是否联网搜索
        private String language;             // 语种
        private String fileUrl;              // 文件地址
        private String fileName;             // 文件名 {带文件名后缀)
        private Boolean isFigure;            // 是否自动配图
        private String aiImage;               // ai配图类型：normal、advanced
    }

    /**
     * 直接生成PPT请求参数
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    @Builder
    public static class CreatePptRequest {
        private String query;                // 用户生成PPT要求（最多8000字）
        private MultipartFile file;          // 上传文件
        private String fileUrl;              // 文件地址
        private String fileName;             // 文件名 {带文件名后缀)
        private String templateId;           // 模板ID
        private String businessId;           // 业务ID（非必传）
        private String author;               // PPT作者名
        private Boolean isCardNote;          // 是否生成PPT演讲备注
        private Boolean search;              // 是否联网搜索
        private String language;             // 语种
        private Boolean isFigure;            // 是否自动配图
        private String aiImage;               // ai配图类型：normal、advanced
    }
}