package cn.com.ctop.toutiao.modules.report.service.impl;

import cn.com.ctop.common.module.utils.Check;
import cn.com.ctop.common.module.utils.CtopAdConstant;
import cn.com.ctop.common.module.vo.ByteDanceReportAccountDailyDTOEntity;
import cn.com.ctop.common.module.vo.SheetInfoVo;
import cn.com.ctop.toutiao.modules.report.DTO.ByteDanceReportAccountDailyDTO;
import cn.com.ctop.toutiao.modules.report.mapper.BytedanceAccountReportMapper;
import cn.com.ctop.toutiao.modules.report.service.IBytedanceAccountReportService;
import cn.com.ctop.toutiao.modules.report.utils.LinkUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.constant.AccountReportConstants;
import org.jeecg.common.constant.SystemDateConstant;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.utils.JsonResourceUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by JQ.bi on 2020.06.05
 */
@Service
public class BytedanceAccountReportServiceImpl implements IBytedanceAccountReportService {

    @Autowired
    BytedanceAccountReportMapper bytedanceAccountReportMapper;

    private static final BigDecimal zero = BigDecimal.ZERO;

    @Override
    public Map<String, Object> getSumDataBy(String mediaId, BigDecimal discount, JSONArray accounts, String startDate, String endDate) {
        Map<String, Object> result = new HashMap<>();
        JSONObject after;
        JSONObject before;
        if (startDate.equals(endDate)) {
            after = bytedanceAccountReportMapper.queryTodaySumReportBy(startDate, accounts);
            if (after == null) {
                return result;
            }
            before = bytedanceAccountReportMapper.queryTodaySumByHour(DateUtils.getAnotherDay(SystemDateConstant.yyyy_MM_dd, startDate, -1), after.getInteger("maxHour"), accounts);
            if (before == null) {
                before = after;
            }
        } else {
            after = bytedanceAccountReportMapper.querySumByStartEndDate(endDate, startDate, accounts);
            if (after == null) {
                return result;
            }
            before = after;
        }
        result.put("Sum", getSumLink(mediaId, discount, after, before));
        return result;
    }

    @Override
    public List<JSONObject> getChartDataBy(String mediaId, BigDecimal discount, JSONArray accounts, String startDate, String endDate) throws ParseException {
        List<JSONObject> result = new ArrayList<>();
        String filedAll = JsonResourceUtil.joinAllFiled(AccountReportConstants.getDictMapBy());
        if (startDate.equals(endDate)) {
            List<JSONObject> after = bytedanceAccountReportMapper.queryTodayDetailReportBy(filedAll, startDate, accounts);
            List<JSONObject> before = bytedanceAccountReportMapper.queryTodayDetailReportBy(filedAll, DateUtils.getAnotherDay(SystemDateConstant.yyyy_MM_dd, startDate, -1), accounts);
            if (after.size() == 0) {
                return result;
            }
            if (before.size() == 0) {
                before = nullDataHandle();
            }
            List<JSONObject> afterDis = this.countDiscountCost(mediaId, discount, after);
            List<JSONObject> beforeDis = this.countDiscountCost(mediaId, discount, before);
            result = LinkUtils.getCompareDate(beforeDis, afterDis, "statHour");
        } else {
            List<JSONObject> after;
            //判断是不是日期间隔大于半年
            if (DateUtils.isMoreSixMonth(startDate, endDate)) {
                after = bytedanceAccountReportMapper.queryDetailGroupMonthByDate(endDate, startDate, accounts);
            } else {
                after = bytedanceAccountReportMapper.queryDetailByStartEndDate(endDate, startDate, accounts);
            }
            if (after == null) {
                return result;
            }
            result = this.countDiscountCost(mediaId, discount, after);
        }
        return result;
    }

    @Override
    public List<JSONObject> getListDataBy(String mediaId, JSONArray accounts, String startDate, String endDate, int hour, String target, String order) {
        List<JSONObject> result;
        String filedAll = JsonResourceUtil.joinAllFiled(AccountReportConstants.getDictMapBy());
        filedAll = filedAll.replace("like_num", "`like`").
                replace("show_num", "`show`").
                replace("convert_num", "`convert`").
                replace("play50_feed_break", "play_50_feed_break").
                replace("play100_feed_break", "play_100_feed_break").
                replace("play25_feed_break", "play_25_feed_break").
                replace("play75_feed_break", "play_75_feed_break");
        if (!Check.isNull(target) && "like_num".equals(target)) {
            target = "`like`";
        } else if ("show_num".equals(target)) {
            target = "`show`";
        } else if ("convert_num".equals(target)) {
            target = "`convert`";
        } else if ("play50_feed_break".equals(target)) {
            target = "play_50_feed_break";
        } else if ("play100_feed_break".equals(target)) {
            target = "play_100_feed_break";
        } else if ("play25_feed_break".equals(target)) {
            target = "play_25_feed_break";
        } else if ("play75_feed_break".equals(target)) {
            target = "play_75_feed_break";
        }
        if (startDate.equals(endDate)) {
            //由于时报数据不准，修改逻辑除当日数据外全部请求日报数据
            if (startDate.equals(DateUtils.date2Str())) {
                result = bytedanceAccountReportMapper.queryTodaySumByHourGroupAccount(filedAll, startDate, hour, accounts, target, order);
                JSONObject afterSum = bytedanceAccountReportMapper.querySumByHour(filedAll, startDate, hour, accounts);
                afterSum.put("authName", "总计");
                JSONObject beforeSum = bytedanceAccountReportMapper.querySumByHour(filedAll, DateUtils.getAnotherDay(SystemDateConstant.yyyy_MM_dd, startDate, -1), hour, accounts);
                beforeSum.put("authName", "昨日总计(相对)");
                result.add(afterSum);
                result.add(beforeSum);
                result.add(countTotal(afterSum, beforeSum));
            } else {
                result = bytedanceAccountReportMapper.querySumByDateGroupAccount(filedAll, endDate, startDate, accounts, target, order);
                JSONObject afterSum = bytedanceAccountReportMapper.queryAllSumByStartEndDate(filedAll, endDate, startDate, accounts);
                afterSum.put("authName", "总计");
                JSONObject beforeSum = bytedanceAccountReportMapper.queryAllSumByStartEndDate(filedAll, DateUtils.getAnotherDay(SystemDateConstant.yyyy_MM_dd, endDate, -1), DateUtils.getAnotherDay(SystemDateConstant.yyyy_MM_dd, startDate, -1), accounts);
                beforeSum.put("authName", "昨日总计(相对)");
                result.add(afterSum);
                result.add(beforeSum);
                result.add(countTotal(afterSum, beforeSum));
            }
        } else {
            if (accounts.size() > 1) {
                result = bytedanceAccountReportMapper.querySumByDateGroupAccount(filedAll, endDate, startDate, accounts, target, order);
            } else {
                result = bytedanceAccountReportMapper.querySumByDateGroupAccountAndDate(filedAll, endDate, startDate, accounts, target, order);
            }
            result.add(bytedanceAccountReportMapper.queryAllSumByStartEndDate(filedAll, endDate, startDate, accounts));
        }
        return result;
    }

    @Override
    public List<JSONObject> getExcelDataBy(String filed, String mediaId, JSONArray accounts, String startDate, String endDate, int hour, String target, String order) {
        List<JSONObject> result;
        if (startDate.equals(endDate)) {
            //由于时报数据不准，修改逻辑除当日数据外全部请求日报数据
            if (startDate.equals(DateUtils.date2Str())) {
                result = bytedanceAccountReportMapper.queryTodaySumByHourGroupAccount(filed, startDate, hour, accounts, target, order);
            } else {
                result = bytedanceAccountReportMapper.querySumByDateGroupAccount(filed, startDate, endDate, accounts, target, order);
            }
        } else {
            result = bytedanceAccountReportMapper.querySumByDateGroupAccount(filed, endDate, startDate, accounts, target, order);
        }
        return result;
    }

    //计算汇总数据环比
    private Map<String, Object> getSumLink(String mediaId, BigDecimal discount, JSONObject after, JSONObject before) {

        Map<String, Object> result = new HashMap<>();

        JSONObject costLink = new JSONObject();
        JSONObject discountCostLink = new JSONObject();
        JSONObject clickLink = new JSONObject();
        JSONObject showNumLink = new JSONObject();
        JSONObject convertNumLink = new JSONObject();

        costLink.put("cost", after.getBigDecimal("cost"));
        costLink.put("CostSumLink", LinkUtils.countLink(after.getBigDecimal("cost"), before.getBigDecimal("cost")));
        if (mediaId.equals(CtopAdConstant.PLATFORM_TYPE_BYTEDANCE)) {
            discountCostLink.put("discountCost", after.getBigDecimal("cost").divide(discount, 4, RoundingMode.HALF_UP));
            discountCostLink.put("discountCostLink", LinkUtils.countLink(after.getBigDecimal("cost").divide(discount, 4, RoundingMode.HALF_UP), before.getBigDecimal("cost").divide(discount, 4, RoundingMode.HALF_UP)));
        } else {
            discountCostLink.put("discountCost", after.getBigDecimal("cost").multiply(discount));
            discountCostLink.put("discountCostLink", LinkUtils.countLink(after.getBigDecimal("cost").multiply(discount), before.getBigDecimal("cost").multiply(discount)));
        }
        clickLink.put("click", after.getBigDecimal("click"));
        clickLink.put("clickLink", LinkUtils.countLink(after.getBigDecimal("click"), before.getBigDecimal("click")));
        showNumLink.put("showNum", after.getBigDecimal("showNum"));
        showNumLink.put("showNumLink", LinkUtils.countLink(after.getBigDecimal("showNum"), before.getBigDecimal("showNum")));
        convertNumLink.put("convertNum", after.getBigDecimal("convertNum"));
        convertNumLink.put("convertNumLink", LinkUtils.countLink(after.getBigDecimal("convertNum"), before.getBigDecimal("convertNum")));
        result.put("costLink", costLink);
        result.put("discountCostLink", discountCostLink);
        result.put("clickLink", clickLink);
        result.put("showNumLink", showNumLink);
        result.put("convertNumLink", convertNumLink);
        return result;
    }

    //计算折后消耗
    private List<JSONObject> countDiscountCost(String mediaId, BigDecimal discount, List<JSONObject> data) {
        if (data.isEmpty()) {
            return data;
        }
        if (mediaId.equals(CtopAdConstant.PLATFORM_TYPE_BYTEDANCE)) {
            data.forEach(it -> {
                it.put("discountCost", it.getBigDecimal("cost").divide(discount, 4, RoundingMode.HALF_UP));
            });
        } else {
            data.forEach(it -> {
                it.put("discountCost", it.getBigDecimal("cost").multiply(discount));
            });
        }
        return data;
    }

    //计算总计环比
    private JSONObject countTotal(JSONObject after, JSONObject before) {
        JSONObject jsonObject = new JSONObject();
        after.forEach((k, v) -> {
            //去除没法计算的字段
            if ("accountId".equals(k) || "authName".equals(k) || v.toString().contains("%") || before.getString(k).contains("%")) {
                jsonObject.put(k, "-");
            } else {
                jsonObject.put(k, (LinkUtils.countLink(after.getBigDecimal(k) == null ? zero : after.getBigDecimal(k), before.getBigDecimal(k) == null ? zero : before.getBigDecimal(k))).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP) + "%");
            }
        });
        jsonObject.put("authName", "环比");
        return jsonObject;
    }

    @Override
    public PageInfo<ByteDanceReportAccountDailyDTO> getBytedanceSaleProjectInfo(String startDate, String endDate, List<Long> projectList, Integer pageNum, Integer pageSize, String sort, Integer yn) {

        if (Check.isNull(projectList)) {
            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            String userId = sysUser.getId();
            String roleCode = bytedanceAccountReportMapper.getRoleCodeByUserId(userId);
            List<Long> mediaIds = new ArrayList<>();
            mediaIds.add(1L);
            mediaIds.add(3L);
            if ("admin".equals(roleCode)) {
                projectList = bytedanceAccountReportMapper.queryProjectInfoByAdmin(mediaIds);
            } else {
                projectList = bytedanceAccountReportMapper.getSaleProjects(userId, mediaIds);
            }
        }
        PageHelper.startPage(pageNum, pageSize);
        List<ByteDanceReportAccountDailyDTO> p = bytedanceAccountReportMapper.getBytedanceProjectInfo(startDate, endDate, projectList, yn);
        return new PageInfo<>(p);
    }

    @Override
    public SheetInfoVo getBytedanceSaleProjectInfoSheetVO(String startDate, String endDate, List<Long> projectList, Integer pageNum, Integer pageSize, String sort, Integer yn) {
        SheetInfoVo vo = new SheetInfoVo<ByteDanceReportAccountDailyDTOEntity>();
        if (Check.isNull(projectList)) {
            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            String userId = sysUser.getId();
            String roleCode = bytedanceAccountReportMapper.getRoleCodeByUserId(userId);

            List<Long> mediaIds = new ArrayList<>();
            mediaIds.add(1L);
            mediaIds.add(3L);

            if ("admin".equals(roleCode)) {
                projectList = bytedanceAccountReportMapper.queryProjectInfoByAdmin(mediaIds);
            } else {
                projectList = bytedanceAccountReportMapper.getSaleProjects(userId, mediaIds);
            }
        }

        PageHelper.startPage(pageNum, pageSize);
        List<ByteDanceReportAccountDailyDTOEntity> dtos = bytedanceAccountReportMapper.getBytedanceProjectInfoEntity(startDate, endDate, projectList, yn);
        vo.setSheetName("头条销售报表");
        vo.setDetails(dtos);
        return vo;
    }

    @Override
    public PageInfo<ByteDanceReportAccountDailyDTO> getBytedanceAccountInfoByProjectId(String startDate, String endDate, Long projectId, Integer pageNo, Integer pageSize, String sort, Integer yn) {

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //String userId = "e9ca23d68d884d4ebb19d07889727dae";
        String userId = sysUser.getId();
        String roleCode = bytedanceAccountReportMapper.getRoleCodeByUserId(userId);

        List<Long> accountIds = null;
        if (projectId == null) {
            if ("admin".equals(roleCode)) {
                accountIds = bytedanceAccountReportMapper.getUserProjectAccountIdsByAdmin();
            } else {
                accountIds = bytedanceAccountReportMapper.getSaleProjectAccountIds(userId);
            }
        }

        if (StringUtils.isBlank(sort)) {
            sort = "cost-";
        }
        sort = sort.replace("-", " desc,").replace("+", " asc,");  //sort=id-name+age+
        sort = sort.substring(0, sort.length() - 1);
        PageHelper.startPage(pageNo, pageSize, sort);
        return new PageInfo<>(bytedanceAccountReportMapper.getBytedanceAccountInfoByProjectId(startDate, endDate, projectId, accountIds, yn));
    }

    private List<JSONObject> nullDataHandle() {
        List<JSONObject> objectList = new ArrayList<>();
        JSONObject jsonObject;
        for (int i = 0; i < 24; i++) {
            jsonObject = new JSONObject();
            jsonObject.put("cost", 0);
            jsonObject.put("showNum", 0);
            jsonObject.put("click", 0);
            jsonObject.put("convertNum", 0);
            jsonObject.put("statHour", i);
            objectList.add(jsonObject);
        }
        return objectList;
    }
}
