package com.yida.data.school.transaction.service.impl;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yida.data.common.core.entity.apply.*;
import com.yida.data.common.core.entity.constant.CachePrefixConstant;
import com.yida.data.common.core.entity.constant.FebsConstant;
import com.yida.data.common.core.entity.job.Job;
import com.yida.data.common.core.entity.system.Dept;
import com.yida.data.common.core.entity.system.SystemUser;
import com.yida.data.common.core.entity.user.EduStudent;
import com.yida.data.job.feign.RemoteJobService;
import com.yida.data.school.dto.transaction.ListBuyStudentDTO;
import com.yida.data.school.dto.transaction.ProductSelectDTO;
import com.yida.data.school.transaction.mapper.EduProductApplyMapper;
import com.yida.data.school.transaction.mapper.EduProductMapper;
import com.yida.data.school.transaction.mapper.EduProductNoticeMapper;
import com.yida.data.school.transaction.service.EduProductApplyService;
import com.yida.data.school.transaction.service.EduProductRealProductService;
import com.yida.data.school.transaction.service.EduProductService;
import com.yida.data.school.vo.transcation.EduProductListVO;
import com.yida.data.school.vo.transcation.EduProductNoticeVO;
import com.yida.data.system.feign.RemoteDeptService;
import com.yida.data.system.feign.RemoteUserService;
import com.yida.data.system.vo.AreaVO;
import com.yida.data.user.feign.RemoteStudentService;
import com.yida.data.user.vo.ParentInfoVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
@AllArgsConstructor
public class EduProductServiceImpl extends ServiceImpl<EduProductMapper, EduProduct> implements EduProductService {

    private static final String JOB_BEAN_NAME = "productUpdateTask";
    private static final String JOB_METHOD_NAME = "productUpdate";
    private static final String JOB_METHOD_NAME2 = "productSendNotice";
    private final EduProductMapper eduProductMapper;
    private final RedisService redisService;
    private final EduProductApplyService eduProductApplyService;
    private final EduProductApplyMapper eduProductApplyMapper;
    private final RemoteJobService remoteJobService;
    private final RemoteStudentService remoteStudentService;
    private final EduProductRealProductService eduProductRealProductService;
    private final RemoteDeptService remoteDeptService;
    private final RemoteUserService remoteUserService;
    @Resource
    private EduProductNoticeMapper eduProductNoticeMapper;

    /**
     * 分页查商品
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public IPage<EduProduct> selectPageEduProductService(Page page, ProductSelectDTO dto) {
        List<Long> schoolIds = new ArrayList<>();
        if (Objects.isNull(dto.getSchoolId())) {
            List<Dept> deptList =
                remoteDeptService.getSchoolByArea(dto.getAreaId(), null).getData();
            if (CollUtil.isNotEmpty(deptList)) {
                log.info("学校列表:[{}]", deptList);
                schoolIds = deptList.stream().map(Dept::getDeptId).collect(Collectors.toList());
            }
        } else {
            schoolIds.add(dto.getSchoolId());
        }
        IPage<EduProduct> iPage = eduProductMapper.selectProductPageList(page, dto, schoolIds);
        iPage.getRecords().forEach(eduProduct -> {
            SystemUser systemUser = remoteUserService.getInfoById(eduProduct.getCreateId()).getData();
            if (Objects.nonNull(systemUser)) {
                eduProduct.setCreateName(systemUser.getNickname());
            }
        });
        return iPage;
    }

    /**
     * 查询单个商品详情
     */
    @Override
    public EduProduct getInfo(Long productId) {
        EduProduct info = baseMapper.getInfo(productId);
        List<EduProductApply> applyList = info.getApplyList();
        if (CollectionUtil.isNotEmpty(applyList)) {
            LocalDate endValidDate = applyList.get(0).getEndValidDate();
            LocalDate beginValidDate = applyList.get(0).getBeginValidDate();
            info.setBeginValidDate(beginValidDate.atTime(0, 0, 0));
            info.setEndValidDate(endValidDate.atTime(0, 0, 0));
        }

        return info;
    }

    /**
     * 商品新增
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertEduProductService(EduProduct eduProduct) {
        //新增商品设置商品区域id
        AreaVO data = remoteDeptService.findAreaById(eduProduct.getSchoolId()).getData();
        eduProduct.setProvinceId(data.getProvinceId());
        eduProduct.setCityId(data.getCityId());
        eduProduct.setCountyId(data.getCountyId());
        eduProduct.setVillageId(data.getVillageId());
        List<Long> schoolIds = eduProduct.getSchoolIds();
        for (Long schoolId : schoolIds) {
            EduProduct realProduct = new EduProduct();
            BeanUtils.copyProperties(eduProduct, realProduct);
            // 保存商品
            if (realProduct.getPutawayDate().isAfter(LocalDateTime.now())) {
                baseMapper.insert(realProduct);
                //定时上架
                Job job = new Job();
                job.setBeanName(JOB_BEAN_NAME);
                job.setMethodName(JOB_METHOD_NAME);
                job.setParams(realProduct.getProductId().toString());
                job.setStatus(Job.ScheduleStatus.NORMAL.getValue());
                LocalDateTime sendDate = eduProduct.getPutawayDate();
                // cron表达式
                String cron = "0" +
                    " " +
                    sendDate.getMinute() +
                    " " +
                    sendDate.getHour() +
                    " " +
                    sendDate.getDayOfMonth() +
                    " " +
                    sendDate.getMonthValue() +
                    " " +
                    "?" +
                    " " +
                    sendDate.getYear();
                job.setCronExpression(cron);
                remoteJobService.saveJob(job);
            } else if (realProduct.getPutawayDate().isBefore(LocalDateTime.now())) {
                //立即上架
                realProduct.setSchoolId(schoolId);
                realProduct.setStatus(1);
                baseMapper.insert(realProduct);
            }
            // 保存商品关联信息
            List<EduProductApply> applyList = realProduct.getApplyList();
            List<EduRealProduct> productList = realProduct.getRealProductList();
            // 保存应用
            if (CollUtil.isNotEmpty(applyList)) {
                for (EduProductApply apply : applyList) {
                    apply.setProductId(realProduct.getProductId());
                    apply.setProductName(realProduct.getProductName());
                }
                eduProductApplyService.saveBatch(applyList);
            }
            // 保存其他商品
            if (CollUtil.isNotEmpty(productList)) {
                List<EduProductRealProduct> realProductList = new ArrayList<>();
                for (EduRealProduct product : productList) {
                    EduProductRealProduct productRealProduct = new EduProductRealProduct();
                    productRealProduct.setProductId(realProduct.getProductId());
                    productRealProduct.setRealProductId(product.getId());
                    realProductList.add(productRealProduct);
                }
                eduProductRealProductService.saveBatch(realProductList);
            }
        }
    }

    /**
     * 删除商品
     *
     * @param productId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeEduProductService(Long productId) {
        eduProductMapper.deleteById(productId);
        eduProductRealProductService.remove(Wrappers.lambdaQuery(new EduProductRealProduct())
            .eq(EduProductRealProduct::getProductId, productId));
        eduProductApplyService.remove(Wrappers.<EduProductApply>lambdaQuery().eq(EduProductApply::getProductId, productId));
        redisService.del(FebsConstant.EDU_PRODUCT + productId);
    }

    /**
     * 修改商品
     *
     * @param eduProduct
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void upDataEduProductService(EduProduct eduProduct) {
        // 删除原有关联信息
        eduProductApplyMapper
            .delete(Wrappers.<EduProductApply>lambdaQuery().eq(EduProductApply::getProductId, eduProduct.getProductId()));
        eduProductRealProductService.remove(Wrappers.<EduProductRealProduct>lambdaQuery().eq(EduProductRealProduct::getProductId,
            eduProduct.getProductId()));
        remoteJobService.delJobByMethod(JOB_BEAN_NAME, JOB_METHOD_NAME, eduProduct.getProductId().toString());

        // 保存商品关联信息
        List<EduProductApply> applyList = eduProduct.getApplyList();
        List<EduRealProduct> productList = eduProduct.getRealProductList();
        // 保存应用
        if (CollUtil.isNotEmpty(applyList)) {
            for (EduProductApply apply : applyList) {
                apply.setProductId(eduProduct.getProductId());
                apply.setProductName(eduProduct.getProductName());
            }
            eduProductApplyService.saveBatch(applyList);
        }

        // 保存商品
        if (eduProduct.getPutawayDate().isAfter(LocalDateTime.now())) {
            baseMapper.updateById(eduProduct);
            //定时上架任务
            Job job = new Job();
            job.setBeanName(JOB_BEAN_NAME);
            job.setMethodName(JOB_METHOD_NAME);
            job.setParams(eduProduct.getProductId().toString());
            job.setStatus(Job.ScheduleStatus.NORMAL.getValue());
            LocalDateTime sendDate = eduProduct.getPutawayDate();
            StringBuilder cron = new StringBuilder();
            // cron表达式
            cron.append("0")
                .append(" ")
                .append(sendDate.getMinute())
                .append(" ")
                .append(sendDate.getHour())
                .append(" ")
                .append(sendDate.getDayOfMonth())
                .append(" ")
                .append(sendDate.getMonthValue())
                .append(" ")
                .append("?")
                .append(" ")
                .append(sendDate.getYear());
            job.setCronExpression(cron.toString());
            remoteJobService.saveJobNoPermission(job);
        } else if (eduProduct.getPutawayDate().isBefore(LocalDateTime.now())) {
            //立即上架
            eduProduct.setStatus(1);
            //立即上架同时查询是否有定时催缴策略，有则创建定时任务
            upDateProductById(eduProduct);
        }

        // 保存其他商品 
        if (CollUtil.isNotEmpty(productList)) {
            List<EduProductRealProduct> realProductList = new ArrayList<>();
            for (EduRealProduct product : productList) {
                EduProductRealProduct productRealProduct = new EduProductRealProduct();
                productRealProduct.setProductId(eduProduct.getProductId());
                productRealProduct.setRealProductId(product.getId());
                realProductList.add(productRealProduct);
            }
            eduProductRealProductService.saveBatch(realProductList);
        }

        // 清除缓存
        redisService.hdel(CachePrefixConstant.PRODUCT, eduProduct.getProductId().toString());
    }

    /**
     * 手机端商品列表
     *
     * @param phone
     * @param schoolId
     * @return
     */
    @Override
    public EduProductListVO selectProductList(String phone, Long schoolId) {
        EduProductListVO eduProductListVO = new EduProductListVO();
        LocalDateTime now = LocalDateTime.now();
        ParentInfoVO data = remoteStudentService.getParentWithStudent(phone, null, schoolId).getData();
        List<Long> studentIds = data.getStudentList().stream().map(x -> x.getStudentId()).collect(Collectors.toList());
        eduProductListVO.setUsing(eduProductMapper.listUsingProduct(studentIds, schoolId, now));
        eduProductListVO.setNotUsing(eduProductMapper.selectProduct(studentIds, schoolId, now));
        return eduProductListVO;
    }

    /**
     * 手机端商品详情
     *
     * @param productId
     * @return
     */
    @Override
    public EduProduct selectProductAndApply(Long productId) {
        return eduProductMapper.selectProductAndApply(productId);
    }

    /**
     * 商品下架
     *
     * @param eduProduct
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void soldOutProduct(EduProduct eduProduct) {
        eduProductMapper.updateById(eduProduct);
        List<EduProductNotice> eduProductNotices = eduProductNoticeMapper.selectList(Wrappers.lambdaQuery(new EduProductNotice())
            .eq(EduProductNotice::getProductId, eduProduct.getProductId()));
        for (EduProductNotice eduProductNotice : eduProductNotices) {
            //删除催缴定时任务
            remoteJobService.delJobByMethod(JOB_BEAN_NAME, JOB_METHOD_NAME2, eduProductNotice.getId().toString());
        }

    }

    @Override
    public List<EduProduct> listOneCategoryProduct(String firstCategory, String secondCategory,
        Long schoolId) {
        return eduProductMapper.listOneCategoryProduct(firstCategory, secondCategory, schoolId);
    }

    @Override
    public Page<EduProductNoticeVO> listBuyStudent(Page page, ListBuyStudentDTO listBuyStudentDTO) {
        if (listBuyStudentDTO.getDateNum() != null) {
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime date = now.plusDays(listBuyStudentDTO.getDateNum());
            listBuyStudentDTO.setDateTime(date);
        }
        return baseMapper.listBuyStudent(page, listBuyStudentDTO);
    }

    @Override
    public Page<EduProductNoticeVO> listNotBuyStudent(ListBuyStudentDTO listBuyStudentDTO) {
        //已购买学生
        List<EduProductNoticeVO> students = baseMapper.listBuyStudent(listBuyStudentDTO);
        List<Long> studentIds = new ArrayList<>();
        for (EduProductNoticeVO student : students) {
            studentIds.add(student.getStudentId());
        }
        listBuyStudentDTO.setStudentId(studentIds);
        //未购买学生
        Page<EduStudent> data = remoteStudentService.listNotBuyStudent(listBuyStudentDTO).getData();
        List<EduStudent> notBuyStudent = data.getRecords();
        //未购买学生id
        List<Long> notBuyId = new ArrayList<>();
        for (EduStudent eduStudent : notBuyStudent) {
            notBuyId.add(eduStudent.getId());
        }
        //获取学生最近一次通知的时间
        List<EduProductNoticeVO> list = baseMapper.getMaxTime(notBuyId, listBuyStudentDTO.getProductId());
        ArrayList<EduProductNoticeVO> listStudent = new ArrayList<>();
        for (EduStudent eduStudent : notBuyStudent) {
            EduProductNoticeVO eduProductNoticeVO = new EduProductNoticeVO();
            eduProductNoticeVO.setCampusName(eduStudent.getCampusName());
            eduProductNoticeVO.setClassName(eduStudent.getClassName());
            eduProductNoticeVO.setGradeName(eduStudent.getGradeName());
            eduProductNoticeVO.setStudentId(eduStudent.getId());
            eduProductNoticeVO.setStudentNumber(eduStudent.getStuNumber());
            eduProductNoticeVO.setStudentName(eduStudent.getStuName());
            listStudent.add(eduProductNoticeVO);
        }

        if (CollectionUtil.isNotEmpty(list)) {
            //往里面加最近一次催缴时间
            for (EduProductNoticeVO lastVo : listStudent) {
                for (EduProductNoticeVO vo : list) {
                    if (lastVo.getStudentId().equals(vo.getStudentId())) {
                        lastVo.setPutDate(vo.getPutDate());
                    }
                }
            }
        }

        //封装分页数据
        Page<EduProductNoticeVO> page = new Page<>();
        page.setRecords(listStudent);
        page.setCurrent(data.getCurrent());
        page.setSize(data.getSize());
        page.setTotal(data.getTotal());
        return page;
    }

    @Override
    public void upDateProductById(EduProduct eduProduct) {

        //判断是否有催缴策略，有则创建定时催缴任务，并生效
        List<EduProductNotice> notices = eduProductNoticeMapper.selectList(Wrappers.lambdaQuery(new EduProductNotice())
            .eq(EduProductNotice::getProductId, eduProduct.getProductId()).isNotNull(EduProductNotice::getSendIntervalDate));
        //有则执行，无则只上架
        if (CollectionUtil.isNotEmpty(notices)) {
            for (EduProductNotice eduProductNotice : notices) {
                if (0 == eduProductNotice.getNoticeType()) {
                    Job job = new Job();
                    job.setBeanName(JOB_BEAN_NAME);
                    job.setMethodName(JOB_METHOD_NAME2);
                    job.setParams(eduProductNotice.getId().toString());
                    job.setStatus(Job.ScheduleStatus.NORMAL.getValue());
                    LocalDateTime sendDate = eduProductNotice.getFirstPutDate().atTime(eduProductNotice.getSendTime());

                    StringBuilder cron = new StringBuilder();
                    // cron表达式
                    cron.append("0")
                        .append(" ")
                        .append(sendDate.getMinute())
                        .append(" ")
                        .append(sendDate.getHour())
                        .append(" ")
                        .append(sendDate.getDayOfMonth()).append("/").append(eduProductNotice.getSendIntervalDate())
                        .append(" ")
                        .append("*")
                        .append(" ")
                        .append("?")
                        .append(" ")
                        .append("*");
                    job.setCronExpression(cron.toString());
                    remoteJobService.saveJobNoPermission(job);
                } else if (eduProductNotice.getNoticeType() == 1) {

                    LocalDateTime minTime = eduProductMapper.getMinTime(eduProduct.getProductId());
                    LocalDate localDate = minTime.toLocalDate();
                    LocalDateTime sendDate = localDate.atTime(eduProductNotice.getSendTime());
                    Job job = new Job();
                    job.setBeanName(JOB_BEAN_NAME);
                    job.setMethodName(JOB_METHOD_NAME2);
                    job.setParams(eduProductNotice.getId().toString());
                    job.setStatus(Job.ScheduleStatus.NORMAL.getValue());
                    // cron表达式
                    String cron = "0" +
                        " " +
                        sendDate.getMinute() +
                        " " +
                        sendDate.getHour() +
                        " " +
                        sendDate.getDayOfMonth() + "/" + eduProductNotice.getSendIntervalDate() +
                        " " +
                        "*" +
                        " " +
                        "?" +
                        " " +
                        "*";
                    job.setCronExpression(cron);
                    remoteJobService.saveJobNoPermission(job);
                }

            }
        }
        //商品上架
        updateById(eduProduct);
    }
}


