package com.pcloud.book.advertising.biz.impl;

import cn.hutool.core.collection.CollUtil;
import com.pcloud.book.advertising.biz.AdvertisingCpaProductPackageBiz;
import com.pcloud.book.advertising.biz.BmBiz;
import com.pcloud.book.advertising.check.AdvertisingCheck;
import com.pcloud.book.advertising.entity.AdvertisingBmOption;
import com.pcloud.book.advertising.entity.AdvertisingBmOptionItem;
import com.pcloud.book.advertising.entity.AdvertisingCpaPaySetting;
import com.pcloud.book.advertising.dao.AdvertisingCpaPaySettingDao;
import com.pcloud.book.advertising.biz.AdvertisingCpaPaySettingBiz;
import com.pcloud.book.advertising.entity.AdvertisingCpaProductPackage;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.NumberUtil;
import com.pcloud.message.common.enums.YesNoEnums;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * (AdvertisingCpaPaySetting)表服务实现类
 *
 * @author makejava
 * @since 2022-11-25 14:20:46
 */
@Service("advertisingCpaPaySettingBiz")
public class AdvertisingCpaPaySettingBizImpl implements AdvertisingCpaPaySettingBiz {

    private static final Logger LOGGER = LoggerFactory.getLogger(AdvertisingCpaPaySettingBizImpl.class);

    @Autowired
    private AdvertisingCpaPaySettingDao advertisingCpaPaySettingDao;
    @Autowired
    private BmBiz bmBiz;
    @Autowired
    private AdvertisingCpaProductPackageBiz cpaProductPackageBiz;
    @Autowired
    private AdvertisingCheck advertisingCheck;

    @Override
    @ParamLog("通过ID查询单条数据")
    public AdvertisingCpaPaySetting getById(Long id) {
        return advertisingCpaPaySettingDao.getById(id);
    }

    @Override
    @ParamLog("查询多条数据")
    public PageBeanNew getList(Integer currentPage, Integer numPerPage) {
        PageBeanNew pageBeanNew = advertisingCpaPaySettingDao.listPageNew(new PageParam(currentPage, numPerPage), null, "getList");
        List recordList = pageBeanNew.getRecordList();
        if (ListUtils.isEmpty(recordList)) {
            return pageBeanNew;
        }
        // 加载其它数据

        return pageBeanNew;
    }

    @Override
    @ParamLog("新增")
    public Long insert(AdvertisingCpaPaySetting advertisingCpaPaySetting) {
        advertisingCpaPaySettingDao.insert(advertisingCpaPaySetting);
        return advertisingCpaPaySetting.getId();
    }

    @Override
    @ParamLog("修改")
    public void update(AdvertisingCpaPaySetting advertisingCpaPaySetting) {
        if (advertisingCpaPaySetting == null || !NumberUtil.isNumber(advertisingCpaPaySetting.getId())) {
            throw BizException.PARAM_IS_NULL;
        }
        advertisingCpaPaySettingDao.update(advertisingCpaPaySetting);
    }

    @Override
    @ParamLog("删除")
    public void deleteById(Long id) {
        advertisingCpaPaySettingDao.deleteById(id);
    }

    @Override
    public void savePaySettingList(List<AdvertisingCpaPaySetting> cpaPaySettingList, Long cpaId, Integer paySetting) {
        if (cpaId == null) {
            return;
        }
        cpaPaySettingList = Optional.ofNullable(cpaPaySettingList).orElse(CollUtil.toList());
        // 查询报名表单
        List<AdvertisingBmOption> bmOptionList = bmBiz.getByCPAId(cpaId);
        // 只匹配年级学科
        Map<String, Long> textMap = bmOptionListConvertToTextMapBy(bmOptionList);
        // 默认将 first 定为 "年级", "年龄"；second 定为 "学科"；(以后如果需要扩展，加一个 firstType，secondType ，然后根据类型处理)
        for (AdvertisingCpaPaySetting cpaPaySetting : cpaPaySettingList) {
            cpaPaySetting.setCpaId(cpaId);
            cpaPaySetting.setFirstOptionItemId(Optional.ofNullable(textMap.get(cpaPaySetting.getFirstOptionItemText())).orElseThrow(() -> new BizException(BizException.PARAM_DELETION.getCode(), "配置支付规则失败，未找到对应的表单字段")));
            cpaPaySetting.setSecondOptionItemId(Optional.ofNullable(textMap.get(cpaPaySetting.getSecondOptionItemText())).orElseThrow(() -> new BizException(BizException.PARAM_DELETION.getCode(), "配置支付规则失败，未找到对应的表单字段")));
            cpaPaySetting.setCreateTime(new Date());
        }
        // 删除已有配置
        advertisingCpaPaySettingDao.deleteByCpaId(cpaId);
        // 保存
        if (CollUtil.isNotEmpty(cpaPaySettingList)) {
            try {
                advertisingCpaPaySettingDao.insert(cpaPaySettingList);
            } catch (DuplicateKeyException e) {
                throw new BizException(BizException.PARAM_DELETION.getCode(), "同一年级/年龄和学科只能设置一条付费规则");
            }
        }
    }

    /**
     * 结构转换
     * 默认为全部字段不重复
     * 目的：没有唯一键id，只能通过 text 拿到 id，然后去保存关系
     * 结构：《文本，id》
     */
    private Map<String, Long> bmOptionListConvertToTextMapBy(List<AdvertisingBmOption> bmOptionList) {
        if (CollUtil.isEmpty(bmOptionList)) {
            return new HashMap<>();
        }
        return bmOptionList.stream()
                .filter(x -> CollUtil.toList("年级", "年龄", "学科").contains(x.getItemTitle()))
                .flatMap(x -> x.getOptionItem().stream())
                .collect(Collectors.toMap(AdvertisingBmOptionItem::getText, AdvertisingBmOptionItem::getId, (v1, v2) -> v1));   // 如果需要 optionId ，那么这里要返回对象，而不只是 getText
    }

    /**
     * 结构（跟上面 bmOptionListConvertToTextMapBy 结果是反的）：《Id，文本》
     */
    private Map<Long, String> bmOptionListConvertToIdMapBy(List<AdvertisingBmOption> bmOptionList) {
        if (CollUtil.isEmpty(bmOptionList)) {
            return new HashMap<>();
        }
        return bmOptionList.stream()
                .filter(x -> CollUtil.toList("年级", "年龄", "学科").contains(x.getItemTitle()))
                .flatMap(x -> x.getOptionItem().stream())
                .collect(Collectors.toMap(AdvertisingBmOptionItem::getId, AdvertisingBmOptionItem::getText, (v1, v2) -> v1));   // 如果需要 optionId ，那么这里要返回对象，而不只是 getText
    }

    @Override
    public List<AdvertisingCpaPaySetting> getByCpaId(Long cpaId, List<AdvertisingBmOption> bmOptionList) {
        List<AdvertisingCpaPaySetting> cpaPaySettingList = Optional.ofNullable(advertisingCpaPaySettingDao.getByCpaId(cpaId)).orElse(CollUtil.toList());
        if (CollUtil.isEmpty(bmOptionList)) {
            bmOptionList = bmBiz.getByCPAId(cpaId);
        }
        // 只匹配年级学科
        Map<Long, String> idMap = bmOptionListConvertToIdMapBy(bmOptionList);
        // 默认将 first 定为 "年级", "年龄"；second 定为 "学科"；(以后如果需要扩展，加一个 firstType，secondType ，然后根据类型处理)
        for (AdvertisingCpaPaySetting cpaPaySetting : cpaPaySettingList) {
            cpaPaySetting.setFirstOptionItemText(idMap.get(cpaPaySetting.getFirstOptionItemId()));
            cpaPaySetting.setSecondOptionItemText(idMap.get(cpaPaySetting.getSecondOptionItemId()));
        }
        return cpaPaySettingList;
    }

    @Override
    public List<AdvertisingCpaPaySetting> cpaPaySetting4WechatListHandler(List<AdvertisingCpaPaySetting> cpaPaySettingList, Integer isWechatUser) {
        if (!YesNoEnums.YES.code.equals(isWechatUser) || CollUtil.isEmpty(cpaPaySettingList)) {
            return CollUtil.toList();
        }
        // 拿到所有的第三方权益包商品信息
        Map<String, AdvertisingCpaProductPackage> cpaProductPackageMap = cpaProductPackageBiz.mapAll();
        // 用来判断是否加入过第一层级
        Map<Long, List<AdvertisingCpaPaySetting>> firstMap = new HashMap<>();
        // 最终嵌套结果
        List<AdvertisingCpaPaySetting> resultList = CollUtil.toList();
        for (AdvertisingCpaPaySetting cpaPaySetting : cpaPaySettingList) {
            List<AdvertisingCpaPaySetting> secondCpaPaySettingList = firstMap.get(cpaPaySetting.getFirstOptionItemId());
            if (CollUtil.isEmpty(secondCpaPaySettingList)) {
                secondCpaPaySettingList = CollUtil.toList();
                // 第二层级为空，说明未加入过第一层级；创建第一层级
                AdvertisingCpaPaySetting firstCpaPaySetting = new AdvertisingCpaPaySetting();
                firstCpaPaySetting.setCpaId(cpaPaySetting.getCpaId());
                firstCpaPaySetting.setFirstOptionItemId(cpaPaySetting.getFirstOptionItemId());
                firstCpaPaySetting.setFirstOptionItemText(cpaPaySetting.getFirstOptionItemText());
                // 设置第二层级
                firstCpaPaySetting.setCpaPaySettingList(secondCpaPaySettingList);
                resultList.add(firstCpaPaySetting);
                // 写入临时变量，用来判断是否加入过第一层级
                firstMap.put(firstCpaPaySetting.getFirstOptionItemId(), secondCpaPaySettingList);
            }
            // 写入第二层级对象
            AdvertisingCpaPaySetting secondCpaPaySetting = new AdvertisingCpaPaySetting();
            secondCpaPaySetting.setId(cpaPaySetting.getId());
            secondCpaPaySetting.setFirstOptionItemId(cpaPaySetting.getFirstOptionItemId());
            secondCpaPaySetting.setFirstOptionItemText(cpaPaySetting.getFirstOptionItemText());
            secondCpaPaySetting.setSecondOptionItemId(cpaPaySetting.getSecondOptionItemId());
            secondCpaPaySetting.setSecondOptionItemText(cpaPaySetting.getSecondOptionItemText());
            secondCpaPaySetting.setProductPackageId(cpaPaySetting.getProductPackageId());
            secondCpaPaySetting.setPayPrice(cpaPaySetting.getPayPrice());
            secondCpaPaySetting.setProductName(cpaProductPackageMap.getOrDefault(cpaPaySetting.getProductPackageId(), new AdvertisingCpaProductPackage()).getProductName());
            secondCpaPaySettingList.add(secondCpaPaySetting);
        }
        return resultList;
    }
}
