package com.fs.newAdv.integration.client.advertiser;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baidu.dev2.thirdparty.jackson.core.JsonProcessingException;
import com.baidu.dev2.thirdparty.jackson.databind.ObjectMapper;
import com.fs.common.constant.SystemConstant;
import com.fs.newAdv.domain.PromotionAccount;
import com.fs.newAdv.domain.SiteStatistics;
import com.fs.newAdv.enums.AdvertiserTypeEnum;
import com.fs.newAdv.integration.client.AbstractApiClient;
import com.fs.newAdv.integration.client.IAccessTokenClient;
import com.fs.newAdv.vo.AccessTokenByAuthCodeVo;
import com.fs.newAdv.vo.AccessTokenVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.utils.URIBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import java.math.BigDecimal;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 巨量引擎API客户端
 * 用于调用巨量引擎的API接口（转化回传等）
 *
 * @author zhangqin
 * @date 2025-11-03
 * @see <a href="https://open.oceanengine.com/labels/7/docs/1696710497745920">巨量引擎API文档</a>
 */
@Slf4j
@Component
public class OceanEngineApiClient extends AbstractApiClient implements IAccessTokenClient {

    /**
     * 巨量引擎转化回传API地址
     */
    private static final String CONVERSION_API_URL = "https://ad.oceanengine.com/track/activate/";
    private static final String REPORT_API_URL = "https://api.oceanengine.com/open_api/v3.0/report/custom/get/";
    /**
     * 获取Access Token
     */
    private static final String ACCESS_TOKEN_URL = "https://api.oceanengine.com/open_api/oauth2/access_token/";
    /**
     * 刷新 Token
     */
    private static final String REFRESH_TOKEN_URL = "https://api.oceanengine.com/open_api/oauth2/refresh_token/";

    /**
     * 回传转化数据到巨量引擎
     *
     * @param conversionData 转化数据
     * @return 是否成功
     */
    @Override
    public boolean reportConversion(Map<String, Object> conversionData) {
        return executeWithLog(AdvertiserTypeEnum.OCEANENGINE, CONVERSION_API_URL, conversionData, () -> {
            // 构建请求参数
            Map<String, Object> requestBody = buildConversionParams(conversionData);
/*            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(CONVERSION_API_URL)
                    .queryParam("callback", requestBody.get("traceId")) // 核心参数，监测链接透传的内容
                    .queryParam("event_type", requestBody.get("event_type"))
                    .queryParam("conv_time", requestBody.get("conv_time"));
            URI uri = builder.build().encode(StandardCharsets.UTF_8).toUri();
            log.info("准备调用巨量引擎回传接口, URL: {}", uri);*/

            // 发送HTTP请求
            return HttpRequest.get(CONVERSION_API_URL)
                    .form(requestBody)
                    .timeout(SystemConstant.API_TIMEOUT)
                    .execute();
        });
    }

    /**
     * 构建转化回传参数
     *
     * @param conversionData 转化数据
     * @return 请求参数
     */
    protected Map<String, Object> buildConversionParams(Map<String, Object> conversionData) {
        Map<String, Object> params = new HashMap<>();

        // 必填参数
        params.put("event_type", conversionData.get("eventType"));
        params.put("callback", conversionData.get("traceId"));
        params.put("conv_time", conversionData.get("timestamp"));
        return params;
    }

    @Override
    public AdvertiserTypeEnum getAdvertiserType() {
        return AdvertiserTypeEnum.OCEANENGINE;
    }

    @Override
    public SiteStatistics getDataReport(PromotionAccount account, String ideaId, String startDate, String endDate) {
        log.info("开始获取头条报表数据：{} {} {} {}",account.getId(), ideaId,startDate,endDate);
        // 构建请求参数
        Map<String, Object> map = new HashMap<>();
        map.put("advertiser_id", Long.valueOf(account.getAdAccountId()));
        // 纬度--天
        map.put("dimensions", Arrays.asList("stat_time_day"));
        // 过滤条件
        Map<String, Object> filters = new HashMap<>();
        filters.put("field", "cdp_promotion_id");
        filters.put("type", 2);
        filters.put("operator", 1);
        filters.put("values", Arrays.asList(ideaId));
        map.put("filters", Arrays.asList(filters));
        /**
         * stat_cost 消耗(元)
         * show_cnt 展示数
         * cpm_platform 平均千次展现费用(元)
         * click_cnt 点击数
         * ctr 点击率
         * cpc_platform 平均点击单价(元)
         * convert_cnt 转化数
         * conversion_cost 平均转化成本
         * conversion_rate 转化率
         */
        map.put("metrics", Arrays.asList("stat_cost",
                "show_cnt", "cpm_platform", "click_cnt", "ctr", "cpc_platform", "cpc_platform", "convert_cnt",
                "conversion_cost", "conversion_rate"));
        map.put("start_time", startDate);
        map.put("end_time", endDate);
        map.put("order_by", Collections.emptyList());
        String url;
        try {
            URIBuilder ub = new URIBuilder(REPORT_API_URL);
            ObjectMapper objectMapper = new ObjectMapper();
            map.forEach((k, v) -> {
                try {
                    ub.addParameter(k, v instanceof String ? (String) v : objectMapper.writeValueAsString(v));
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }
            });
            url = ub.build().toURL().toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        HttpResponse execute = HttpRequest.get(url)
                .header("Access-Token", getAccessToken(account.getId()))
                .timeout(SystemConstant.API_TIMEOUT)
                .execute();
        String body = execute.body();
        log.info("头条报表数据返回：{} ",body);
        JSONObject jsonObject = JSONUtil.parseObj(body);
        JSONObject data = jsonObject.getJSONObject("data");
        int code = jsonObject.getInt("code");
        if (code != 0){
            log.error("头条报表数据返回异常：{} ",body);
            return new SiteStatistics();
        }
        JSONArray rows = data.getJSONArray("rows");
        JSONObject jsonObject1 = rows.getJSONObject(0);
        JSONObject jsonObject2 = jsonObject1.getJSONObject("metrics");
        SiteStatistics siteStatistics = new SiteStatistics();
        siteStatistics.setImpressionCount(Integer.valueOf(jsonObject2.getStr("show_cnt")));
        siteStatistics.setClickCount(Integer.valueOf(jsonObject2.getStr("click_cnt")));
        siteStatistics.setActualCost(new BigDecimal(jsonObject2.getStr("stat_cost")));
        siteStatistics.setAccountCost(new BigDecimal(jsonObject2.getStr("stat_cost")));
        siteStatistics.setClickRate(new BigDecimal(jsonObject2.getStr("ctr")));
        siteStatistics.setAvgClickPrice(new BigDecimal(jsonObject2.getStr("cpc_platform")));
        return siteStatistics;
    }


    @Override
    public AccessTokenVo refreshAccessToken(PromotionAccount promotionAccount) {
        return executeToken(this::getAccessTokenVo, () -> {
            Map<String, Object> map = new HashMap<>();
            map.put("app_id", promotionAccount.getAppId());
            map.put("secret", promotionAccount.getAppSecret());
            map.put("refresh_token", promotionAccount.getRefreshToken());
            // 发送HTTP请求
            return HttpRequest.post(REFRESH_TOKEN_URL)
                    .header("Content-Type", "application/json")
                    .body(JSONUtil.toJsonStr(map))
                    .timeout(SystemConstant.API_TIMEOUT)
                    .execute();
        });
    }


    @Override
    public AccessTokenVo getAccessTokenByAuthCode(AccessTokenByAuthCodeVo request) {
        return executeToken(this::getAccessTokenVo, () -> {
            // 调用接口换取授权令牌
            Map<String, Object> map = new HashMap<>();
            map.put("app_id", request.getAppId());
            map.put("secret", request.getAppSecret());
            map.put("auth_code", request.getAuthCode());
            // 发送HTTP请求
            return HttpRequest.post(ACCESS_TOKEN_URL)
                    .header("Content-Type", "application/json")
                    .body(JSONUtil.toJsonStr(map))
                    .timeout(SystemConstant.API_TIMEOUT)
                    .execute();
        });
    }

    public AccessTokenVo getAccessTokenVo(JSONObject res) {
        JSONObject data = res.getJSONObject("data");
        return AccessTokenVo.builder()
                .accessToken((String) data.get("access_token"))
                .refreshToken((String) data.get("refresh_token"))
                .expireTime(LocalDateTime.now().plusSeconds(data.getLong("refresh_token_expires_in")))
                .build();
    }

}

