package com.xxl.job.executor.report.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.executor.common.entity.CtopOauthToken;
import com.xxl.job.executor.common.service.ICtopOauthTokenService;
import com.xxl.job.executor.entity.vo.ByteDanceAdvertiserReportDTO;
import com.xxl.job.executor.material.service.IByteDanceAdvertiserDataService;
import com.xxl.job.executor.report.entity.*;
import com.xxl.job.executor.report.mapper.BytedanceReportMaterialDailyMapper;
import com.xxl.job.executor.report.service.*;
import com.xxl.job.executor.utils.*;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author 宋英豪
 */
@Slf4j
@Service
@Primary

public class ReportServiceImpl implements IReportService {
    @Autowired
    private ICtopOauthTokenService tokenService;
    @Autowired
    private IBytedanceAdvertiserDailyReportService advertiserDailyReportService;
    @Autowired
    private IBytedanceAdvertiserHourlyReportService advertiserHourlyReportService;
    @Autowired
    private IBytedanceCampaignDailyReportService campaignDailyReportService;
    @Autowired
    private IBytedanceCampaignHourlyReportService campaignHourlyReportService;
    @Autowired
    private IBytedancePlanDailyReportService planDailyReportService;
    @Autowired
    private IBytedancePlanHourlyReportService planHourlyReportService;
    @Autowired
    private IBytedanceCreativeDailyReportService creativeDailyReportService;
    @Autowired
    private IBytedanceCreativeHourlyReportService creativeHourlyReportService;
    @Autowired
    private BytedanceReportMaterialDailyMapper materialDailyMapper;
    @Autowired
    private IBytedanceReportService bytedanceReportService;
    @Autowired
    private IByteDanceVideoReportDailyService byteDanceVideoReportDailyService;
    @Autowired
    private IByteDanceAdvertiserDataService advertiserDataService;
    @Autowired
    private IBytedanceInterfaceService bytedanceInterfaceService;
    @Autowired
    private IBytedanceReportMaterialRetryService retryService;


    @Override
    public void getAdvertiserReport(CtopOauthToken token, Date startDate, Date endDate, String bytedanceReportTypePl) {
        var conditions = getReportDTO(token, startDate, endDate, bytedanceReportTypePl);
        getAdvertiserReportByPage(token, conditions, 1);
    }

    private void getAdvertiserReportByPage(CtopOauthToken token, ByteDanceAdvertiserReportDTO conditions, Integer page) {
        conditions.setPage(page);
        SerializeConfig config = new SerializeConfig();
        config.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(conditions, config));
        JSONObject getObject = getAdvertiserStat(token, jsonObject);
        if(null == getObject){
            XxlJobHelper.log("头条广告主数据获取异常");
            return;
        }
        Integer code = getObject.getInteger("code");
        String message = getObject.getString("message");
        if (null == code || code != 0) {
            XxlJobHelper.log("头条广告主数据获取异常：{}", message);
            return;
        }
        JSONArray dataArray = getObject.getJSONObject("data").getJSONArray("list");
        if (null == dataArray || dataArray.isEmpty()) {
            return;
        }

        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject data = dataArray.getJSONObject(i);
            if (null != conditions.getTimeGranularity() && conditions.getTimeGranularity().equals(CtopAdConstant.BYTEDANCE_REPORT_TYPE_HOURLY)) {
                BytedanceAdvertiserHourlyReport hourlyReport = new BytedanceAdvertiserHourlyReport(data);
                advertiserHourlyReportService.saveOrUpdate(hourlyReport);
            } else {
                BytedanceAdvertiserDailyReport dailyReport = new BytedanceAdvertiserDailyReport(data);
                advertiserDailyReportService.saveOrUpdate(dailyReport);
            }
        }
        getAdvertiserReportByPage(token, conditions, page + 1);
    }

    @Override
    public void getAdvertiserCampaignReport(CtopOauthToken token, Date startDate, Date endDate, String bytedanceReportTypePl) {
        var conditions = getReportDTO(token, startDate, endDate, bytedanceReportTypePl);
        getCampaignReportByPage(token, conditions, 1);
    }

    private void getCampaignReportByPage(CtopOauthToken token, ByteDanceAdvertiserReportDTO conditions, int page) {
        conditions.setPage(page);
        SerializeConfig config = new SerializeConfig();
        config.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(conditions, config));
        JSONObject getObject = getCampaignStat(token, jsonObject);
        Integer code = getObject.getInteger("code");
        String message = getObject.getString("message");
        if (null == code || code != 0) {
            log.error("广告组报表数据获取异常：{}", message);
            return;
        }
        JSONArray dataArray = getObject.getJSONObject("data").getJSONArray("list");
        if (null == dataArray || dataArray.isEmpty()) {
            log.info("广告组报表信息为空=》accountId:{}", token.getAccountId());
            return;
        }
        for (var i = 0; i < dataArray.size(); i++) {
            var data = dataArray.getJSONObject(i);
            if (null != conditions.getTimeGranularity() && CtopAdConstant.BYTEDANCE_REPORT_TYPE_HOURLY.equals(conditions.getTimeGranularity())) {
                var hourlyReport = new BytedanceCampaignHourlyReport(data, token.getAccountId());
                campaignHourlyReportService.saveOrUpdate(hourlyReport);
            } else {
                var dailyReport = new BytedanceCampaignDailyReport(data, token.getAccountId());
                campaignDailyReportService.saveOrUpdate(dailyReport);
            }
        }
        getCampaignReportByPage(token, conditions, page + 1);
    }


    @Override
    public void getAdvertiserPlanReport(CtopOauthToken token, Date startDate, Date endDate, String bytedanceReportTypePl) {
        var conditions = getReportDTO(token, startDate, endDate, bytedanceReportTypePl);
        getPlanReportByPage(token, conditions, 1);
    }

    private void getPlanReportByPage(CtopOauthToken token, ByteDanceAdvertiserReportDTO conditions, int page) {
        conditions.setPage(page);
        var config = new SerializeConfig();
        config.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
        var jsonObject = JSONObject.parseObject(JSON.toJSONString(conditions, config));

        JSONObject getObject = getAdStat(token, jsonObject);
        if (null == getObject) {
            log.error("广告计划报表数据获取异常=》account：{}；message:{}", token.getAccountId(), "返回数据异常");
            return;
        }
        Integer code = getObject.getInteger("code");
        var message = getObject.getString("message");
        if (null == code || code != 0) {
            log.error("广告计划报表数据获取异常=》account：{}；message:{}", token.getAccountId(), message);
            return;
        }
        var dataArray = getObject.getJSONObject("data").getJSONArray("list");
        if (null == dataArray || dataArray.size() <= 0) {
            return;
        }
        List<BytedancePlanHourlyReport> hourlyReports = new ArrayList<>();
        List<BytedancePlanDailyReport> dailyReports = new ArrayList<>();
        for (var i = 0; i < dataArray.size(); i++) {
            var data = dataArray.getJSONObject(i);
            if (null != conditions.getTimeGranularity() && CtopAdConstant.BYTEDANCE_REPORT_TYPE_HOURLY.equals(conditions.getTimeGranularity())) {
                var hourlyReport = new BytedancePlanHourlyReport(data, token.getAccountId());
                String adName = hourlyReport.getAdName();
                String[] tags = adName.split("-");
                hourlyReport.setChannelCode(tags[0]);
                hourlyReports.add(hourlyReport);
            } else {
                var dailyReport = new BytedancePlanDailyReport(data, token.getAccountId());
                //获取计划详情
                dailyReports.add(dailyReport);
            }
        }

        if (null != conditions.getTimeGranularity() && CtopAdConstant.BYTEDANCE_REPORT_TYPE_HOURLY.equals(conditions.getTimeGranularity())) {
            planHourlyReportService.replaceBatch(hourlyReports);
        } else {
            planDailyReportService.replaceBatch(dailyReports);
        }

        getPlanReportByPage(token, conditions, page + 1);
    }

    @Override
    public void getAdvertiserCreativeReport(CtopOauthToken token, Date startDate, Date endDate, String bytedanceReportTypePl) {
        var conditions = getReportDTO(token, startDate, endDate, bytedanceReportTypePl);
        getCreativeReportByPage(token, conditions, 1);
    }


    public JSONObject getMaterialReport(CtopOauthToken token, String startDate, String endDate, Integer pageNum) {
        // 请求地址
        String url = "https://ad.oceanengine.com/open_api/2/report/integrated/get/";
        // 请求参数
        JSONObject params = new JSONObject();
        params.put("advertiser_id", token.getAccountId());
        params.put("start_date", startDate);
        params.put("end_date", endDate);
        params.put("page", pageNum);
        params.put("page_size", 100);
        JSONArray groupBy = new JSONArray();
        groupBy.add("STAT_GROUP_BY_MATERIAL_ID");
        groupBy.add("STAT_GROUP_BY_TIME_DAY");
        groupBy.add("STAT_GROUP_BY_INVENTORY");
        groupBy.add("STAT_GROUP_BY_IMAGE_MODE");
        params.put("group_by", groupBy);
        return HttpUtils.bytedanceGetRequest(token.getAccessToken(), url, params);
    }

    @Override
    public void getMaterialReportByPage(CtopOauthToken token, String startDate, String endDate, Integer pageNum) {
        JSONObject getObject = getMaterialReport(token, startDate, endDate, pageNum);
        if (null == getObject) {
            BytedanceReportMaterialRetry reportMaterialRetry = new BytedanceReportMaterialRetry();
            reportMaterialRetry.setAccountId(token.getAccountId());
            reportMaterialRetry.setStartDate(startDate);
            reportMaterialRetry.setStartDate(endDate);
            reportMaterialRetry.setStatus(0);
            retryService.save(reportMaterialRetry);
            log.error("素材报表请求数据null=>accountId:{};startDate:{};endDate:{}", token.getAccountId(), startDate, endDate);
            return;
        }
        Integer code = getObject.getInteger("code");
        String message = getObject.getString("message");
        if (null == code || code != 0) {
            log.error("素材报表数据获取异常：{}", message);
            return;
        }
        JSONArray dataArray = getObject.getJSONObject("data").getJSONArray("list");
        if (null == dataArray || dataArray.size() <= 0) {
            return;
        }
        List<BytedanceReportMaterialDaily> dailyReports = new ArrayList<>();
        for (var i = 0; i < dataArray.size(); i++) {
            var data = dataArray.getJSONObject(i);
            var dailyReport = new BytedanceReportMaterialDaily(data, token.getAccountId());
            dailyReports.add(dailyReport);
        }
        materialDailyMapper.replaceIntoBatch(dailyReports);
        Integer totalNum = getObject.getJSONObject("data").getJSONObject("page_info").getInteger("total_page");
        if (null != totalNum && totalNum > pageNum) {
            getMaterialReportByPage(token, startDate, endDate, pageNum + 1);
        }
    }


    @Override
    public void loadBytedanceHistoryData(CtopOauthToken token) {
        for (int i = 1; i < 180; i++) {
            Date getDate = DateUtils.addDay(new Date(), -i);
            this.getAdvertiserCreativeReport(token, getDate, getDate, CtopAdConstant.BYTEDANCE_REPORT_TYPE_DAILY);
            this.getAdvertiserPlanReport(token, getDate, getDate, CtopAdConstant.BYTEDANCE_REPORT_TYPE_DAILY);
            this.getAdvertiserReport(token, getDate, getDate, CtopAdConstant.BYTEDANCE_REPORT_TYPE_DAILY);
        }

        try {
            advertiserDataService.getMaterialList(token);
            log.info("获取历史素材报表：accountId：{}", token.getAccountId());
            String nowDate = DateUtils.getNowDate("yyyy-MM-dd");
            String endDate = DateUtils.addDay(nowDate, -180);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            Date end = simpleDateFormat.parse(nowDate);
            Date start = simpleDateFormat.parse(endDate);
            List<Date> dates = DateUtils.findDates(start, end);
            for (int i = 0; i < dates.size(); i++) {
                String formatDate = simpleDateFormat.format(dates.get(i));
                //试玩报表
                bytedanceInterfaceService.bytedancePlayableReport(token,formatDate,formatDate);
                //
                //素材报表
                int code = bytedanceReportService.bytedanceMaterialReport(token, formatDate, formatDate);
                //如果成功的话跑视频清洗数据方法，失败会进入重试库，重试成功后再清洗数据
                if (code == 200 || code == 1) {
                    byteDanceVideoReportDailyService.videoInfoListByAccountId(formatDate, formatDate, token.getAccountId());
                }
                //
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private ByteDanceAdvertiserReportDTO getReportDTO(CtopOauthToken token, Date startDate, Date endDate, String bytedanceReportTypePl) {
        var conditions = new ByteDanceAdvertiserReportDTO();
        conditions.setAdvertiserId(token.getAccountId());
        conditions.setStartDate(DateUtils.formatDate(startDate));
        conditions.setEndDate(DateUtils.formatDate(endDate));
        conditions.setPageSize(1000);
        conditions.setTimeGranularity(bytedanceReportTypePl);
        return conditions;
    }


    private void getCreativeReportByPage(CtopOauthToken token, ByteDanceAdvertiserReportDTO conditions, int page) {
        conditions.setPage(page);
        var config = new SerializeConfig();
        config.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
        var jsonObject = JSONObject.parseObject(JSON.toJSONString(conditions, config));
        var getObject = getCreativeStat(token, jsonObject);
        var code = getObject.getInteger("code");
        var message = getObject.getString("message");
        if (null == code || code != 0) {
            log.error("广告创意报表数据获取异常：{}", message);
            return;
        }
        JSONArray dataArray = getObject.getJSONObject("data").getJSONArray("list");
        if (null == dataArray || dataArray.size() <= 0) {
            return;
        }
        List<BytedanceCreativeHourlyReport> hourlyReports = new ArrayList<>();
        List<BytedanceCreativeDailyReport> dailyReports = new ArrayList<>();
        for (var i = 0; i < dataArray.size(); i++) {
            var data = dataArray.getJSONObject(i);
            if (null != conditions.getTimeGranularity() && CtopAdConstant.BYTEDANCE_REPORT_TYPE_HOURLY.equals(conditions.getTimeGranularity())) {
                var hourlyReport = new BytedanceCreativeHourlyReport(data, token.getAccountId());
                hourlyReports.add(hourlyReport);
            } else {
                var dailyReport = new BytedanceCreativeDailyReport(data, token.getAccountId());

                Long creativeId = dailyReport.getCreativeId();
                String signature = creativeHourlyReportService.getSignatureByCreativeId(creativeId);
                if (!Check.isNull(signature)) {
                    dailyReport.setSignature(signature);
                }
                dailyReports.add(dailyReport);
            }
        }

        if (null != conditions.getTimeGranularity() && CtopAdConstant.BYTEDANCE_REPORT_TYPE_HOURLY.equals(conditions.getTimeGranularity())) {
            creativeHourlyReportService.replaceBatch(hourlyReports);
        } else {
            creativeDailyReportService.replaceBatch(dailyReports);
        }
        getCreativeReportByPage(token, conditions, page + 1);
    }

    @Override
    public Map<String, Object> getAgentReport(JSONObject conditions) {
        Long accountId = conditions.getLong("accountId");
        CtopOauthToken token = tokenService.getOauthTokenByAccountId(accountId + "");
        return getCreativeStat(token, conditions);
    }

    /**
     * 获取广告创意报表信息
     *
     * @param token
     * @param conditions
     * @return
     */
    public JSONObject getCreativeStat(CtopOauthToken token, JSONObject conditions) {
        // 请求地址
        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_ad_creative_get");
        JSONArray groupBy = new JSONArray();
        groupBy.add("STAT_GROUP_BY_FIELD_ID");
        groupBy.add("STAT_GROUP_BY_FIELD_STAT_TIME");
        conditions.put("group_by", groupBy);
        return HttpUtils.bytedanceGetRequest(token.getAccessToken(), url, conditions);
    }

    /**
     * 获取广告计划报表信息
     *
     * @param token
     * @param conditions
     * @return
     */
    private JSONObject getAdStat(CtopOauthToken token, JSONObject conditions) {
        // 请求地址
        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_ad_report_get");
        JSONArray groupBy = new JSONArray();
        groupBy.add("STAT_GROUP_BY_FIELD_ID");
        groupBy.add("STAT_GROUP_BY_FIELD_STAT_TIME");
        JSONObject status = new JSONObject();
        status.put("status","AD_STATUS_ALL");
        conditions.put("filtering",status);
        conditions.put("group_by", groupBy);
        return HttpUtils.bytedanceGetRequest(token.getAccessToken(), url, conditions);
    }

    /**
     * 获取广告组报表信息
     *
     * @param token
     * @param conditions
     * @return
     */
    public JSONObject getCampaignStat(CtopOauthToken token, JSONObject conditions) {
        // 请求地址
        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_campaign_report_get");
        JSONArray groupBy = new JSONArray();
        groupBy.add("STAT_GROUP_BY_FIELD_ID");
        groupBy.add("STAT_GROUP_BY_FIELD_STAT_TIME");
        conditions.put("group_by", groupBy);
        return HttpUtils.bytedanceGetRequest(token.getAccessToken(), url, conditions);
    }

    /**
     * 获取广告主报表信息
     *
     * @param token
     * @param conditions
     * @return
     */
    public JSONObject getAdvertiserStat(CtopOauthToken token, JSONObject conditions) {
        // 请求地址
        String url = PropertiesUtils.getValue("bytedance_config", "bytedance_api_url") + PropertiesUtils.getValue("bytedance_config", "bytedance_v2_advertiser_report_get");
        JSONArray groupBy = new JSONArray();
        groupBy.add("STAT_GROUP_BY_FIELD_ID");
        groupBy.add("STAT_GROUP_BY_FIELD_STAT_TIME");
        conditions.put("group_by", groupBy);
        return HttpUtils.bytedanceGetRequest(token.getAccessToken(), url, conditions);
    }
}
