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

import cn.hutool.core.util.StrUtil;
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.fs.common.constant.SystemConstant;
import com.fs.common.exception.ThirdPartyException;
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.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 百度营销API客户端
 * 用于调用百度营销的API接口（转化回传等）
 *
 * @author zhangqin
 * @date 2025-11-03
 * @see <a href="https://dev2.baidu.com/content?sceneType=0&pageId=101211&nodeId=658">百度营销API文档</a>
 */
@Slf4j
@Component
public class BaiduApiClient extends AbstractApiClient implements IAccessTokenClient {

    /**
     * 百度OCPC转化回传API地址
     */
    private static final String CONVERSION_API_URL = "https://ocpc.baidu.com/ocpcapi/api/uploadConvertData";
    private static final String REPORT_DATA_API_URL = "https://api.baidu.com/json/sms/service/OpenApiReportService/getReportData";
    private static final String ACCESS_TOKEN_URL = "https://u.baidu.com/oauth/accessToken";
    private static final String REFRESH_TOKEN_URL = "https://u.baidu.com/oauth/refreshToken";


    /**
     * 回传转化数据到百度
     *
     * @param conversionData 转化数据
     * @return 是否成功
     */
    @Override
    public boolean reportConversion(Map<String, Object> conversionData) {
        return executeWithLog(AdvertiserTypeEnum.OCEANENGINE, CONVERSION_API_URL, conversionData, () -> {
            // 构建请求参数
            Map<String, Object> stringObjectMap = buildConversionParams(conversionData);
            // 发送HTTP请求
            return HttpRequest.post(CONVERSION_API_URL)
                    .header("Content-Type", "application/json")
                    .body(JSONUtil.toJsonStr(stringObjectMap))
                    .timeout(SystemConstant.API_TIMEOUT)
                    .execute();
        });

    }

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

        // 必填参数
        String token = (String) conversionData.get("accessToken");
        if (StrUtil.isBlank(token)) {
            throw new ThirdPartyException("token不能为空");
        }
        params.put("token", token);

        // 转化数据列表
        List<Map<String, Object>> conversionList = new ArrayList<>();
        Map<String, Object> conversion = new HashMap<>();

        // 点击ID（必填）
        String logidUrl = (String) conversionData.get("viewUrl");
        if (StrUtil.isBlank(logidUrl)) {
            throw new ThirdPartyException("落地页不能为空");
        }
        conversion.put("logidUrl", logidUrl);

        // 转化类型（必填）
        conversion.put("newType", conversionData.get("eventType"));

        // 转化时间（毫秒时间戳）
        Long conversionTime = (Long) conversionData.get("timestamp");
        if (conversionTime == null) {
            conversionTime = System.currentTimeMillis() / 1000;
        }
        conversion.put("convertTime", conversionTime);

        // 转化价值（可选）
        if (conversionData.containsKey("value")) {
            conversion.put("convertValue", conversionData.get("value"));
        }

        conversionList.add(conversion);
        params.put("conversionTypes", conversionList);

        return params;
    }

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

    @Override
    public SiteStatistics getDataReport(PromotionAccount account, String ideaId, String startDate, String endDate) {
        // 构建请求参数
        Map<String, Object> map = new HashMap<>();
        Map<String, Object> header = new HashMap<>();
        header.put("accessToken", account.getAccessToken());
        header.put("userName", account.getExtendedField());
        map.put("header", header);
        Map<String, Object> body = new HashMap<>();
        // 基础信息
        //报告名称: 信息流整体账户报告
        //reportType: 2172649
        //支持的时间单位: HOUR DAY WEEK MONTH SUMMARY
        //支持的最大时间区间: 824天
        body.put("reportType", 2172649);
        // 查询当天的数据
        LocalDateTime yesterday = LocalDateTime.now().minusDays(1);
        body.put("startDate", startDate);
        body.put("endDate", endDate);
        body.put("timeUnit", "DAY");
        body.put("userIds", Collections.singletonList(account.getAdAccountId()));
        // 基础指标
        body.put("columns", Arrays.asList("impression", "click", "cost", "ctr", "cpc", "cpm", "phoneButtonClicks"));
        body.put("startRow", 0);
        body.put("rowCount", 1000);
        Map<String,Object> filters = new HashMap<>();
        filters.put("column","adGroupId");
        filters.put("operator","IN");
        filters.put("values",Arrays.asList(ideaId));
        body.put("filters", filters);
        map.put("body", body);
        log.info("百度数据请求参数：{}", JSONUtil.toJsonStr(map));
        HttpResponse execute = HttpRequest.post(REPORT_DATA_API_URL)
                .header("Content-Type", "application/json")
                .body(JSONUtil.toJsonStr(map))
                .timeout(SystemConstant.API_TIMEOUT)
                .execute();
        JSONObject jsonObject = JSONUtil.parseObj(execute.body());
        log.info("百度数据返回结果：{}", execute.body());
        JSONObject data = jsonObject.getJSONObject("body").getJSONObject("data");
        JSONArray rows = data.getJSONArray("rows");
        JSONObject jsonObject1 = rows.getJSONObject(0);
        SiteStatistics siteStatistics = new SiteStatistics();
        siteStatistics.setImpressionCount(Integer.valueOf(jsonObject1.getStr("impression")));
        siteStatistics.setClickCount(Integer.valueOf(jsonObject1.getStr("click")));
        siteStatistics.setActualCost(new BigDecimal(jsonObject1.getStr("cost")));
        siteStatistics.setAccountCost(new BigDecimal(jsonObject1.getStr("cost")));
        siteStatistics.setClickRate(new BigDecimal(jsonObject1.getStr("ctr")));
        siteStatistics.setAvgClickPrice(new BigDecimal(jsonObject1.getStr("cpc")));
        return siteStatistics;
    }


    @Override
    public AccessTokenVo refreshAccessToken(PromotionAccount promotionAccount) {
        return executeToken(this::getAccessTokenVo, () -> {
            // 调用接口换取授权令牌
            Map<String, Object> requestMap = new HashMap<>();
            requestMap.put("appId", promotionAccount.getAppId());
            requestMap.put("secretKey", promotionAccount.getAppSecret());
            requestMap.put("refreshToken", promotionAccount.getRefreshToken());
            requestMap.put("userId", promotionAccount.getAdAccountId());
            // 发送HTTP请求
            return HttpRequest.post(REFRESH_TOKEN_URL)
                    .header("Content-Type", "application/json")
                    .body(JSONUtil.toJsonStr(requestMap))
                    .timeout(SystemConstant.API_TIMEOUT)
                    .execute();
        });
    }

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

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

