package com.ruoyi.demo.service.impl;

import cn.hutool.core.lang.Dict;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.demo.entity.*;
import com.ruoyi.demo.entity.bo.CallBackBean;
import com.ruoyi.demo.entity.bo.PlanAddBo;
import com.ruoyi.demo.entity.bo.PlanBo;
import com.ruoyi.demo.entity.bo.PlanItemAddBo;
import com.ruoyi.demo.entity.vo.*;
import com.ruoyi.demo.mapper.*;
import com.ruoyi.demo.service.PlanService;
import com.ruoyi.demo.utils.OnStateUtil;
import com.ruoyi.demo.utils.SendCallBackUtil;
import com.ruoyi.demo.utils.SignUtil;
import com.ruoyi.demo.utils.StateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class PlanServiceImpl implements PlanService {
    @Autowired
    PlanMapper planMapper;
    @Autowired
    PlanItemMapper planItemMapper;
    @Autowired
    PlanAuditMapper planAuditMapper;
    @Autowired
    AppMapper appMapper;
    @Autowired
    CommercialMapper commercialMapper;
    @Autowired
    SystemSetterMapper systemSetterMapper;
    @Autowired
    StoreMapper storeMapper;
    @Autowired
    PlanPushStatisticsMapper planPushStatisticsMapper;
    @Autowired
    AddrCategoryMapper addrCategoryMapper;
    @Autowired
    EquipmentMapper equipmentMapper;
    @Autowired
    GoodsMapper goodsMapper;
    @Autowired
    StatisticsMapper statisticsMapper;
    @Autowired
    ExposureMapper exposureMapper;
//    @Autowired
//    SysUserMapper sysUserMapper;

    @Override
    public String getSign(PlanAddBo bo) {
        QueryWrapper<App> appQueryWrapper = new QueryWrapper<>();
        appQueryWrapper.eq("appkey",bo.getAppkey());
        appQueryWrapper.eq("state",1);
        appQueryWrapper.eq("deleted","0");
        App app = appMapper.selectOne(appQueryWrapper);
        if (app == null)
            return "error";
        Map<String,Object> params = Dict.create()
            .set("appkey",bo.getAppkey())
            .set("goodsId",bo.getGoodsId())
            .set("goodsImg",bo.getGoodsImg())
            .set("goodsIntroduce",bo.getGoodsIntroduce())
            .set("goodsLogo",bo.getGoodsLogo())
            .set("goodsName",bo.getGoodsName())
            .set("goodsClassify",bo.getGoodsClassify())
            .set("goodsPrice",bo.getGoodsPrice())
            .set("items",bo.getItems())
            .set("planEndTime",bo.getPlanEndTime())
            .set("planStartTime",bo.getPlanStartTime())
            .set("sign",null)
            .set("vendorId",bo.getVendorId())
            .set("vendorName",bo.getVendorName());
        return SignUtil.sign(params,app.getAppSecret());
    }

    @Override
    public int addPlan(PlanAddBo bo) {
        QueryWrapper<App> appQueryWrapper = new QueryWrapper<>();
        appQueryWrapper.eq("appkey",bo.getAppkey());
        appQueryWrapper.eq("state",1);
        appQueryWrapper.eq("deleted","0");
        App app = appMapper.selectOne(appQueryWrapper);
        if (app == null)
            return -1;
        Map<String,Object> params = Dict.create()
            .set("appkey",bo.getAppkey())
            .set("goodsId",bo.getGoodsId())
            .set("goodsImg",bo.getGoodsImg())
            .set("goodsIntroduce",bo.getGoodsIntroduce())
            .set("goodsLogo",bo.getGoodsLogo())
            .set("goodsName",bo.getGoodsName())
            .set("goodsClassify",bo.getGoodsClassify())
            .set("goodsPrice",bo.getGoodsPrice())
            .set("items",bo.getItems())
            .set("planEndTime",bo.getPlanEndTime())
            .set("planStartTime",bo.getPlanStartTime())
            .set("sign",bo.getSign())
            .set("vendorId",bo.getVendorId())
            .set("vendorName",bo.getVendorName());
        if (!SignUtil.verify(params,app.getAppSecret()))
            return -3;
        // 插入广告计划
        Plan plan = new Plan(app,bo);
        planMapper.insert(plan);
        // 插入广告计划明细
        for (PlanItemAddBo itemAddBo : bo.getItems()) {
            PlanItem item = new PlanItem(plan.getPlanId(), itemAddBo);
            planItemMapper.insert(item);
        }
        // 插入商品信息
        QueryWrapper<Goods> goodsQueryWrapper = new QueryWrapper<>();
        goodsQueryWrapper.eq("appkey",bo.getAppkey());
        goodsQueryWrapper.eq("goods_id",bo.getGoodsId());
        goodsQueryWrapper.eq("vendor_id",bo.getVendorId());
        Goods query = goodsMapper.selectOne(goodsQueryWrapper);
        if (query == null){
            Goods goods = new Goods(plan);
            goodsMapper.insert(goods);
        }
        return 1;
    }

    @Override
    public int deletePlan(String id) {
        QueryWrapper<PlanItem> itemQueryWrapper = new QueryWrapper<>();
        itemQueryWrapper.eq("plan_id",id);
        planItemMapper.delete(itemQueryWrapper);
        QueryWrapper<Plan> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("plan_id",id);
        return planMapper.delete(queryWrapper);
    }

    @Override
    public int deletePlans(List<String> ids) {
        int i = 0;
        for (String id : ids){
            QueryWrapper<Plan> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("plan_id",id);
            i += planMapper.delete(queryWrapper);
        }
        return i;
    }

    @Override
    public int checkPlan(PlanBo bo,Long userId,String userName) {
        QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
        planQueryWrapper.eq("plan_id",bo.getPlanId());
        planQueryWrapper.eq("deleted","0");
        Plan plan = planMapper.selectOne(planQueryWrapper);
        if (plan == null)
            return -1;
        // 没有该app或者该app已经被禁用，则不允许审核
        QueryWrapper<App> appQueryWrapper = new QueryWrapper<>();
        appQueryWrapper.eq("appkey",plan.getAppkey());
        appQueryWrapper.eq("state",1);
        appQueryWrapper.eq("deleted","0");
        App app = appMapper.selectOne(appQueryWrapper);
        if (app == null)
            return -1;

        plan.setState(bo.getState());
        int i = planMapper.updateById(plan);
        if (i == 0)
            return 0;
//        SysUser sysUser = sysUserMapper.selectById(userId);
        PlanAudit audit = new PlanAudit(bo,userId.toString(),userName);
        int insert = planAuditMapper.insert(audit);
        if (insert == 1){
            CallBackBean callBackBean = new CallBackBean();
            callBackBean.setAuditPerson(userName);
            if (bo.getState() == 1)
                callBackBean.setAuditComment("审核通过");
            else callBackBean.setAuditComment("审核不通过");
            callBackBean.setAuditTime(LocalDateTime.now(ZoneId.of("Asia/Shanghai")));
            SendCallBackUtil.sendCallBack(app.getCallBack(),callBackBean);
        }
        return insert;
    }

    @Override
    public PageInfo<List<PlanListVo>> getPlanList(PlanBo bo) {
        PageHelper.startPage(bo.getPageNum(), bo.getPageSize(),true);
        QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
        if (bo.getText() != null)
            planQueryWrapper.and(planQueryWrapper1 -> {
                planQueryWrapper1.like("plan_id",bo.getText())
                    .or()
                    .like("plan_name",bo.getText())
                    .or()
                    .like("principal_name",bo.getText())
                    .or()
                    .like("principal_telephone",bo.getText());
            });
        if (bo.getStartTime() != null)
            planQueryWrapper.apply("plan_create_time >= STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",bo.getStartTime());
        if (bo.getEndTime() != null)
            planQueryWrapper.apply("plan_create_time <= STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",bo.getEndTime());
        planQueryWrapper.eq("state", StateUtil.APPROVED);
        planQueryWrapper.eq("deleted","0");
        List<Plan> plans = planMapper.selectList(planQueryWrapper);
        List<PlanListVo> vos = new ArrayList<>();
        for (Plan plan : plans){
            vos.add(new PlanListVo(plan));
        }
        return new PageInfo(vos);
    }

    @Override
    public PlanDetailVo getPlanDetail(String planId) {
        QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
        planQueryWrapper.eq("plan_id",planId);
        planQueryWrapper.eq("deleted","0");
        Plan plan = planMapper.selectOne(planQueryWrapper);
        if (plan == null)
            return null;
        QueryWrapper<PlanItem> itemQueryWrapper = new QueryWrapper<>();
        itemQueryWrapper.eq("plan_id",planId);
        List<PlanItem> items = planItemMapper.selectList(itemQueryWrapper);
        List<PlanItemVo> itemVos = new ArrayList<>();
        if (items != null)
            for (PlanItem item : items){
                itemVos.add(new PlanItemVo(item));
            }
        PlanDetailVo vo = new PlanDetailVo(plan, itemVos);
        return vo;
    }

    @Override
    public List<PlanPushVo> getPlanPush(String equipmentId) {
//        根据设备id查询可投放的广告计划
//        再根据每个广告计划id，查询其商品信息
        List<PlanPushVo> pushVos = new ArrayList<>();
        QueryWrapper<PlanItem> itemQueryWrapper = new QueryWrapper<>();
        itemQueryWrapper.eq("equipment_id",equipmentId);
        itemQueryWrapper.eq("deleted","0");
        List<PlanItem> items = planItemMapper.selectList(itemQueryWrapper);
        for (PlanItem item : items){
            QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
            planQueryWrapper.apply("plan_start_time <= STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",LocalDateTime.now(ZoneId.of("Asia/Shanghai")));
            planQueryWrapper.apply("plan_end_time > STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",LocalDateTime.now(ZoneId.of("Asia/Shanghai")));
            planQueryWrapper.eq("plan_id",item.getPlanId());
            planQueryWrapper.eq("state",StateUtil.APPROVED);
            planQueryWrapper.eq("deleted","0");
            Plan plan = planMapper.selectOne(planQueryWrapper);
            if (plan != null)
                pushVos.add(new PlanPushVo(item,plan));
        }
        return pushVos;
    }

    @Override
    public List<PlanPushVo> getPlanPushByCode(String equipmentCode) {
        List<PlanPushVo> pushVos = new ArrayList<>();
        QueryWrapper<PlanItem> itemQueryWrapper = new QueryWrapper<>();
        itemQueryWrapper.eq("equipment_code",equipmentCode);
        itemQueryWrapper.eq("deleted","0");
        List<PlanItem> items = planItemMapper.selectList(itemQueryWrapper);
        items.sort(Comparator.comparing(PlanItem::getSort).reversed());
        for (PlanItem item : items){
            QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
            planQueryWrapper.eq("plan_id",item.getPlanId());
            planQueryWrapper.apply("plan_start_time <= STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",LocalDateTime.now(ZoneId.of("Asia/Shanghai")));
            planQueryWrapper.apply("plan_end_time > STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",LocalDateTime.now(ZoneId.of("Asia/Shanghai")));
            planQueryWrapper.eq("state",StateUtil.APPROVED);
            planQueryWrapper.eq("on_state", OnStateUtil.UP);
            planQueryWrapper.eq("deleted","0");
            Plan plan = planMapper.selectOne(planQueryWrapper);
            if (plan != null)
                pushVos.add(new PlanPushVo(item,plan));
        }
        return pushVos;
    }

    @Override
    public int planUpDown(String planId) {
        QueryWrapper<Plan> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("plan_id",planId);
        queryWrapper.eq("deleted","0");
        Plan plan = planMapper.selectOne(queryWrapper);
        if (plan == null)
            return -1;
        plan.setOnState(plan.getOnState()+1);
        if (plan.getOnState() >= 2)
            plan.setOnState(0);
        return planMapper.updateById(plan);
    }

    @Override
    public PageInfo<List<PlanManageListVo>> getPlanManageList(PlanBo bo) {
        PageHelper.startPage(bo.getPageNum(),bo.getPageSize(),true);
        QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
        planQueryWrapper.eq("state",bo.getState());
        if (bo.getText() != null)
            planQueryWrapper.and(planQueryWrapper1 -> {
                planQueryWrapper1.like("plan_id",bo.getText())
                    .or()
                    .like("app_name",bo.getText())
                    .or()
                    .like("commercial_name",bo.getText());
            });
        if (bo.getStartTime() != null)
            planQueryWrapper.apply("plan_start_time >= STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",bo.getStartTime());
        if (bo.getEndTime() != null)
            planQueryWrapper.apply("plan_end_time <= STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",bo.getEndTime());
        planQueryWrapper.eq("deleted","0");
        List<Plan> plans = planMapper.selectList(planQueryWrapper);
        List<PlanManageListVo> vos = new ArrayList<>();
        for (Plan plan : plans){
            PlanManageListVo vo = new PlanManageListVo(plan);
            Integer count = planItemMapper.selectEquipmentCountByPlanId(plan.getPlanId());
            vo.setEquipmentCount(count);
            vos.add(vo);
        }
        return new PageInfo(vos);
    }

    @Override
    public PlanManageDetailVo getPlanManageDetail(String planId) {
        QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
        planQueryWrapper.eq("plan_id",planId);
        planQueryWrapper.eq("deleted","0");
        Plan plan = planMapper.selectOne(planQueryWrapper);
        if (plan == null)
            return null;
        QueryWrapper<PlanItem> itemQueryWrapper = new QueryWrapper<>();
        itemQueryWrapper.eq("plan_id",planId);
        itemQueryWrapper.eq("deleted","0");
        List<PlanItem> items = planItemMapper.selectList(itemQueryWrapper);
        List<PlanManageItemVo> itemVos = new ArrayList<>();
        for (PlanItem item : items){
            PlanManageItemVo itemVo = new PlanManageItemVo(item);
            if (item.getStoreId() != null){
                Store store = storeMapper.selectById(item.getStoreId());
                if (store != null)
                    itemVo.setStoreName(store.getStoreName());
            }
            itemVos.add(itemVo);
        }
        PlanManageDetailVo vo = new PlanManageDetailVo(plan, itemVos);
        return vo;
    }

    @Override
    public PageInfo<List<PlanPushListVo>> getPlanPushList(PlanBo bo) {
        PageHelper.startPage(bo.getPageNum(),bo.getPageSize(),true);
        QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
        planQueryWrapper.eq("appkey",bo.getAppkey());
//        planQueryWrapper.eq("commercial_id",bo.getCommercialId());
        if (bo.getText() != null)
            planQueryWrapper.and(planQueryWrapper1 -> {
                planQueryWrapper1.like("plan_id",bo.getText())
                    .or()
                    .like("plan_name",bo.getText())
                    .or()
                    .like("principal_name",bo.getText())
                    .or()
                    .like("principal_telephone",bo.getText());
            });
        if (bo.getStartTime() != null)
            planQueryWrapper.apply("plan_start_time >= STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",bo.getStartTime());
        if (bo.getEndTime() != null)
            planQueryWrapper.apply("plan_end_time <= STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",bo.getEndTime());
        planQueryWrapper.eq("deleted","0");
        List<Plan> plans = planMapper.selectList(planQueryWrapper);
        List<PlanPushListVo> vos = new ArrayList<>();
        for (Plan plan : plans){
            PlanPushListVo vo = new PlanPushListVo(plan);
            Integer count = planItemMapper.selectEquipmentCountByPlanId(plan.getPlanId());
            vo.setEquipmentCount(count);
            vos.add(vo);
        }
        return new PageInfo(vos);
    }

    @Override
    public PageInfo<List<PlanPushStatisticsListVo>> getPlanPushStatisticsList(PlanBo bo) {
        PageHelper.startPage(bo.getPageNum(),bo.getPageSize(),true);
        QueryWrapper<PlanPushStatistics> statisticsQueryWrapper = new QueryWrapper<>();
        if (bo.getText() != null)
            statisticsQueryWrapper.and(planPushStatisticsQueryWrapper -> {
                planPushStatisticsQueryWrapper.like("equipment_id",bo.getText())
                    .or()
                    .like("equipment_code",bo.getText())
                    .or()
                    .like("equipment_name",bo.getText());
            });
        if (bo.getStartTime() != null)
            statisticsQueryWrapper.apply("laster_time >= STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",bo.getStartTime());
        if (bo.getEndTime() != null)
            statisticsQueryWrapper.apply("laster_time <= STR_TO_DATE({0},'%Y-%m-%d %H:%i:%s')",bo.getEndTime());
        List<PlanPushStatistics> list = planPushStatisticsMapper.selectList(statisticsQueryWrapper);
        List<PlanPushStatisticsListVo> vos = new ArrayList<>();
        for (PlanPushStatistics statistics : list){
            vos.add(new PlanPushStatisticsListVo(statistics));
        }
        return new PageInfo(vos);
    }

    @Override
    public void planPushStatisticsStart() {
        // 清除当前月的统计记录
        QueryWrapper<PlanPushStatistics> planPushStatisticsQueryWrapper = new QueryWrapper<>();
        planPushStatisticsQueryWrapper.apply("DATE_FORMAT(laster_time,'%Y-%m') = DATE_FORMAT({0},'%Y-%m')",LocalDateTime.now(ZoneId.of("Asia/Shanghai")));
        planPushStatisticsMapper.delete(planPushStatisticsQueryWrapper);
        // 获取所有设备，遍历
        for (Equipment equipment : equipmentMapper.selectList(null)) {
            // 先查询设备下所有plan_item，再根据item_id统计查询曝光记录表获取曝光次数
            List<String> ids = planItemMapper.getItemIdsByCode(equipment.getEquipmentCode());
            Integer carousalCount = exposureMapper.selectTotalCountByItemIds(ids);
            // 统计查询统计信息表获取累计扫码量、累计交易数、累计用户数、累计收入
            Integer scanCount = statisticsMapper.selectScanByEquipmentCode(equipment.getEquipmentCode());
            Integer tradeCount = statisticsMapper.selectDealCountByEquipmentCode(equipment.getEquipmentCode());
            List<String> users = statisticsMapper.selectUserIdsByEquipmentCode(equipment.getEquipmentCode());
            Float totalPrice = statisticsMapper.selectTotalPriceByEquipmentCode(equipment.getEquipmentCode());
            // 插入记录
            PlanPushStatistics planPushStatistics = new PlanPushStatistics();
            planPushStatistics.setEquipmentId(equipment.getEquipmentId());
            planPushStatistics.setEquipmentName(equipment.getEquipmentName());
            planPushStatistics.setEquipmentCode(equipment.getEquipmentCode());
            planPushStatistics.setCarouselCount(carousalCount);
            planPushStatistics.setScanCodeCount(scanCount);
            planPushStatistics.setTradeCount(tradeCount);
            if (users == null)
                planPushStatistics.setTotalUserCount(0);
            else
                planPushStatistics.setTotalUserCount(users.size());
            if (totalPrice == null)
                planPushStatistics.setTotalPrice(Float.valueOf(0));
            else
                planPushStatistics.setTotalPrice(totalPrice);
            planPushStatistics.setLasterTime(LocalDateTime.now(ZoneId.of("Asia/Shanghai")));
            planPushStatisticsMapper.insert(planPushStatistics);
        }
    }

    @Override
    public PlanHomeVo getPlanTotal() {
        PlanHomeVo vo = new PlanHomeVo();
        vo.setTotal(planMapper.selectPlanTotal());
        return vo;
    }

    @Override
    public List<AddrCategory> getAddrCategory() {
        return addrCategoryMapper.selectList(null);
    }

    @Override
    public List<AddrCategory> getAddrCategoryLevel(String code,String level) {
        if ("province".equals(level)){
            QueryWrapper<AddrCategory> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("city","");
            return addrCategoryMapper.selectList(queryWrapper);
        }else if("city".equals(level)){
            QueryWrapper<AddrCategory> queryWrapper = new QueryWrapper<>();
            queryWrapper.likeRight("addr_code",code.substring(0,2));
            queryWrapper.and(categoryQueryWrapper -> {
                categoryQueryWrapper.eq("district", "").and(addrCategoryQueryWrapper -> {
                    addrCategoryQueryWrapper.ne("city", "");
                });
            });
            return addrCategoryMapper.selectList(queryWrapper);
        }else if("zone".equals(level)){
            QueryWrapper<AddrCategory> queryWrapper = new QueryWrapper<>();
            queryWrapper.likeRight("addr_code",code.substring(0,4));
            queryWrapper.and(categoryQueryWrapper -> {
                categoryQueryWrapper.ne("district", "");
            });
            return addrCategoryMapper.selectList(queryWrapper);
        }
        return null;
    }

    @Override
    public PageInfo<List<Equipment>> getEquipments(PlanBo bo) {
        PageHelper.startPage(bo.getPageNum(),bo.getPageSize(),true);
        QueryWrapper<Equipment> equipmentQueryWrapper = new QueryWrapper<>();
        equipmentQueryWrapper.eq("state",1);
        if (bo.getText() != null)
            equipmentQueryWrapper.and(equipmentQueryWrapper1 -> {
                equipmentQueryWrapper1.like("equipment_id",bo.getText())
                    .or()
                    .like("equipment_code",bo.getText())
                    .or()
                    .like("equipment_name",bo.getText());
            });
        if (bo.getAddrCodes() != null){
            for (String addrCode : bo.getAddrCodes()){
                String province = String.valueOf(addrCode.charAt(0))+String.valueOf(addrCode.charAt(1));
                String city = String.valueOf(addrCode.charAt(2))+String.valueOf(addrCode.charAt(3));
                String district = String.valueOf(addrCode.charAt(4))+String.valueOf(addrCode.charAt(5));
                if (district.equals("00")){
                    if (city.equals("00"))
                        equipmentQueryWrapper.or().likeRight("addr_code",province);
                    else
                        equipmentQueryWrapper.or().likeRight("addr_code",province+city);
                }else
                    equipmentQueryWrapper.or().likeRight("addr_code",province+city+district);
            }
        }
        return new PageInfo(equipmentMapper.selectList(equipmentQueryWrapper));
    }
}
