package com.fkzy.warn.service.impl;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fkzy.warn.common.constants.LawResearchUrlConstants;
import com.fkzy.warn.common.util.MD5Util;
import com.fkzy.warn.common.util.RedisUtil;
import com.fkzy.warn.mapper.LawCaseMapper;
import com.fkzy.warn.model.*;
import com.fkzy.warn.model.params.AILawParams;
import com.fkzy.warn.model.params.LawGroupParam;
import com.fkzy.warn.model.params.PageParam;
import com.fkzy.warn.service.FyApiService;
import com.fkzy.warn.service.InvocationRecordService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.BufferedSource;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author zhangjing
 * @date 2023/10/16 18:17
 * @description
 */
@Slf4j
@Service
public class FyApiServiceImpl extends ServiceImpl<LawCaseMapper, LawCase> implements FyApiService {

    @Value(value = "${api.accessTokenUrl}")
    private String accessTokenUrl;

    @Value(value = "${api.appKey}")
    private String appKey;
    @Value(value = "${api.appSecret}")
    private String appSecret;

    @Value(value = "${api.lawGroupUrl}")
    private String lawGroupUrl;

    @Value(value = "${api.lawGroupInfoUrl}")
    private String lawGroupInfoUrl;

    @Value(value = "${api.aiLawUrl}")
    private String aiLawUrl;

    @Value(value = "${api.apiId}")
    private String apiId;
    @Resource
    RedisUtil redisUtil;
    @Resource
    InvocationRecordService invocationRecordService;


    @Override
    public void getAccessToken() {
        try {
            String result = postAccessToken(accessTokenUrl, appKey, appSecret);
            ApiResult<AccessToken> apiResult = JSON.parseObject(
                result,
                new TypeReference<ApiResult<AccessToken>>() {
                }
            );
            if (apiResult != null && apiResult.getCode().equals(1000)) {
                String accessKey = apiResult.getData().getAccessKey();
                redisUtil.del("accessKey");
                redisUtil.set("accessKey", accessKey, 60 * 48);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void getLawGroup(LawGroupParam lawGroupParam) {
//        getAccessToken();
//        if (true){
//            return;
//        }

        PageParam pageParam = new PageParam();
        pageParam.setPageNum(1);
        pageParam.setPageSize(20);
        String json = JSON.toJSONString(lawGroupParam);
        HttpHeaders headers = getRequestHeader(json);
        String result = postAip(lawGroupUrl, headers, json, "法研平台-法律法规分组列表");
        ApiResult<LawPageData<LawGroup>> resultData = JSON.parseObject(
            result,
            new TypeReference<ApiResult<LawPageData<LawGroup>>>() {
            }
        );
    }

    @Override
    public void getLawGroupInfo(String id) {
        JSONObject object = new JSONObject();
        object.put("id", id);
        String json = object.toJSONString();
        HttpHeaders headers = getRequestHeader(json);
        String result = postAip(lawGroupInfoUrl, headers, json, "法研平台-法律法规详情");
        ApiResult<LawGroupInfo> resultData = JSON.parseObject(
            result,
            new TypeReference<ApiResult<LawGroupInfo>>() {
            }
        );
    }

    @Override
    public void sendAILaw(AILawParams aiLawParams) {
//        getAccessToken();
//        if (true) {
//            return;
//        }
        String jsonParams = JSON.toJSONString(aiLawParams);
        HttpHeaders headers = getRequestHeader(jsonParams);
        postStream(aiLawUrl, headers, jsonParams, "法研平台-AI检索法规");
    }
    /**
     * 发送流式请求到指定URL，并处理SSE响应
     *
     * @param url         请求的完整URL
     * @param headers     已经构建好的请求头，应包含认证等信息
     * @param jsonParams  JSON格式的请求体
     * @param logDesc     用于日志描述的标识
     */
    public void postStream(String url, HttpHeaders headers, String jsonParams, String logDesc) {


        // 1. 创建 OkHttpClient 实例
        OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            // SSE是长连接，设置较长的读取超时
            .readTimeout(5, TimeUnit.MINUTES)
            .build();

        // 2. 构建 Request
        okhttp3.MediaType JSON_TYPE = okhttp3.MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(JSON_TYPE, jsonParams);

        Request.Builder requestBuilder = new Request.Builder()
            .url(url)
            .post(body);

        // 将 Spring 的 HttpHeaders 复制到 OkHttp 的 Request.Builder 中
        for (String headerName : headers.keySet()) {
            String headerValue = headers.getFirst(headerName);
            if (headerValue != null) {
                requestBuilder.addHeader(headerName, headerValue);
            }
        }

        Request request = requestBuilder.build();

        // 3. 发起异步请求
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                System.err.println(logDesc + " - 请求失败: " + e.getMessage());
                e.printStackTrace();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {
                    if (!response.isSuccessful()) {
                        System.err.println(logDesc + " - 请求失败，状态码: " + response.code());
                        System.err.println(logDesc + " - 错误响应体: " + response.body().string());
                        return;
                    }

                    // 检查 Content-Type
                    String contentType = response.header("Content-Type");
                    if (contentType != null && contentType.toLowerCase().contains("text/event-stream")) {
                        System.out.println(logDesc + " - 检测到 content-type: " + contentType);
                    } else {
                        System.err.println(logDesc + " - 警告: 响应的 content-type 不是 'text/event-stream': " + contentType);
                    }

                    // 获取响应体源
                    ResponseBody responseBody = response.body();
                    if (responseBody == null) {
                        System.err.println(logDesc + " - 响应体为空");
                        return;
                    }

                    BufferedSource source = responseBody.source();

                    System.out.println(logDesc + " - 请求成功，开始处理流式响应...");

                    // 4. 逐行读取并处理流
                    while (!source.exhausted()) {
                        String line = source.readUtf8LineStrict();


                        if (line.startsWith("data:")) {
                            // 提取 data 字段后的 JSON 内容
                            String jsonData = line.substring(5).trim(); // 去掉 "data:" 前缀和空格
                            try {
                                // 假设服务器返回的 data 是 JSON，可以使用 Fastjson2 解析
                                Object parsedData = JSON.parse(jsonData);
                                System.out.println(logDesc + " - 收到数据: " + parsedData);
                                // 在这里，你可以将 parsedData 转换为你需要的对象类型，
                                // 并进行后续的业务处理
                            } catch (Exception e) {
                                // 如果 data 不是 JSON，直接打印
                                System.out.println(logDesc + " - 收到非JSON数据: " + jsonData);
                            }
                        } else if (line.startsWith("event:") || line.startsWith("id:") || line.startsWith("retry:")) {
                            // 处理其他 SSE 事件字段 (如果需要)
                            System.out.println(logDesc + " - SSE Event Line: " + line);
                        } else if (line.isEmpty()) {
                            // SSE 规范中，空行表示一个事件的结束
                            // System.out.println(logDesc + " - Event End (empty line)");
                        } else {
                            // 有些服务器可能直接发送数据而不带 "data:" 前缀
                            System.out.println(logDesc + " - Received raw line: " + line);
                        }
                    }
                    System.out.println(logDesc + " - 流式响应处理完毕。");

                } finally {
                    response.close(); // 确保资源被释放
                }
            }
        });

        System.out.println(logDesc + " - 异步请求已发送，正在监听流式响应...");
    }
    private String postAip(String lawGroupUrl, HttpHeaders headers
        , String request, String apiName) {
        //接口调用日志
        InvocationRecord invocationRecord = new InvocationRecord();

        RestTemplate restTemplate = new RestTemplate();
        HttpComponentsClientHttpRequestFactory requestFactory
            = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setConnectionRequestTimeout(60000);
        requestFactory.setConnectTimeout(60000);
        requestFactory.setReadTimeout(60000);
        restTemplate.setRequestFactory(requestFactory);
        try {
            HttpEntity<String> entity = new HttpEntity<>(request, headers);
            ResponseEntity<String> response = restTemplate.exchange(
                lawGroupUrl,
                HttpMethod.POST,
                entity,
                String.class
            );

            String rawResponseBody = response.getBody();
            String resultData;

            // 获取响应头中的 Content-Type
            String contentType = response.getHeaders().getContentType().toString();
            if (contentType != null && contentType.toLowerCase().contains("charset=utf-8")) {
                // 指定了UTF-8，则使用UTF-8解码
                resultData = new String(rawResponseBody.getBytes("ISO-8859-1"), "UTF-8");
            } else {
                // 兜底
                resultData = new String(rawResponseBody.getBytes("ISO-8859-1"), "UTF-8");
            }

            //日志
            invocationRecord.setApiUrl(lawGroupUrl);
            if (request != null) {
                invocationRecord.setInputObj(request);
            }
            invocationRecord.setApiName(apiName);
            invocationRecord.setIsSuccess(0);
            invocationRecord.setApiResult(resultData);
            JSONObject jsonObject = JSONObject.parseObject(resultData);
            if (jsonObject != null && jsonObject.getString("code").equals("1000")) {
                invocationRecord.setIsSuccess(1);
                return resultData;
            }

        } catch (Exception e) {
            // 记录失败情况
            invocationRecord.setIsSuccess(0);
            invocationRecord.setApiResult("Error: " + e.getMessage());
            e.printStackTrace(); // 或者使用更合适的日志框架
        } finally {
            // 无论成功还是失败，都确保记录被保存
            invocationRecordService.save(invocationRecord);
        }
        return null;
    }

    private HttpHeaders getRequestHeader(String params) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set("FYDN-OP-RequestId", UUID.randomUUID().toString().replaceAll("-", ""));
        // 签名串，使用在线文档中的MD5Util示例加密生成
        String sortString = MD5Util.sortJsonToStr(params);
        String sign = MD5Util.md5Sign(sortString, appKey);
        headers.set("FYDN-OP-Sign", sign);
        // 需要从getAccessToken返回结果中解析出accessKey，返回结构样例参考在线文档
        String  accessToken = getRedisAccessToken();
        headers.set("FYDN-OP-AccessToken", accessToken);
        headers.set("FYDN-OP-AppID", apiId);
        // 调用的环境（prod:线上环境，默认；test:测试环境）
        headers.set("FYDN-OP-Env", "prod");
        // 用户所在系统的唯一标识
        headers.set("FYDN-OP-UserId", "");
        return headers;
    }

    private String getRedisAccessToken() {
        String accessToken = redisUtil.getString("accessKey");
        if (accessToken == null) {
            getAccessToken();
            accessToken = redisUtil.getString("accessKey");
        }
        if (accessToken != null && accessToken.startsWith("\"") && accessToken.endsWith("\"")) {
            // 使用 substring 去掉第一个和最后一个字符
            return accessToken.substring(1, accessToken.length() - 1);
        }
        return accessToken;
    }

    public String postAccessToken(String apiUrl, String appKey, String appSecret) throws Exception {
        // 将 paramMap 转为 JSON 字符串

        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
            HttpPost httpPost = new HttpPost(apiUrl);

            RequestConfig config = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000).setConnectionRequestTimeout(10000).build();
            httpPost.setConfig(config);

            // 构造 x-www-form-urlencoded 参数
            String params = "appKey=" + URLEncoder.encode(appKey, StandardCharsets.UTF_8.toString()) + "&appSecret=" + URLEncoder.encode(appSecret, StandardCharsets.UTF_8.toString());

            StringEntity entity = new StringEntity(params, StandardCharsets.UTF_8);
            httpPost.setEntity(entity);
            httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    org.apache.http.HttpEntity resEntity = response.getEntity();
                    return EntityUtils.toString(resEntity, StandardCharsets.UTF_8);
                } else {
                    System.err.println("HTTP Error: " + statusCode);
                    return null;
                }
            }
        }
    }


}
