package com.fs.store.service.impl;

import java.time.LocalDateTime;
import java.util.*;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.fs.common.core.domain.R;
import com.fs.common.utils.DateUtils;
import com.fs.store.cache.IFsUserCacheService;
import com.fs.store.cache.impl.IFsStoreOrderCacheServiceImpl;
import com.fs.store.cache.impl.IFsUserCacheServiceImpl;
import com.fs.store.domain.*;
import com.fs.store.dto.TemplateMessageSendRequestDTO;
import com.fs.store.enums.IcgProcessStatusEnum;
import com.fs.store.enums.IcgScheduleOperationTypeEnum;
import com.fs.store.enums.MiniAppNotifyTaskStatusEnum;
import com.fs.store.mapper.*;
import com.fs.store.param.FsStoreCouponReceiveParam;
import com.fs.store.service.IFsCouponScheduleService;
import com.fs.store.service.IFsStoreCouponIssueService;
import com.github.pagehelper.util.StringUtil;
import com.hc.openapi.tool.util.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * 定时发放优惠券队列Service业务层处理
 *
 * @author fs
 * @date 2025-03-08
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FsCouponScheduleServiceImpl implements IFsCouponScheduleService
{
    /**
     * 优惠券定时任务
     */
    private final FsCouponScheduleMapper fsCouponScheduleMapper;
    /**
     * 优惠券领取Service接口
     */
    private final IFsStoreCouponIssueService fsStoreCouponIssueService;
    /**
     * 优惠券发放计划日志表Mapper接口
     */
    private final FsCouponScheduleLogMapper fsCouponScheduleLogMapper;
    /**
     * 优惠券表Mapper接口
     */
    private final FsStoreCouponMapper fsStoreCouponMapper;

    /**
     * 用户表Mapper接口
     */
    private final FsUserMapper fsUserMapper;

    /**
     * 优惠券发放计划日志表Mapper接口
     */
    private final FsMiniprogramSubNotifyTaskMapper fsMiniprogramSubNotifyTaskMapper;

    /**
     * 小程序消息通知任务名称
     */
    private final String WX_MINI_APP_NOTIFY_TASK_NAME = "优惠券发放";

    /**
     * 小程序消息通知模板ID
     */
//    private final String WX_MINI_APP_NOTIFY_TEMPLATE_ID = "5ZSzz2nPmJo9EuenZa78mQPScoOMc84LnEfEpV0-i04";
    private final String WX_MINI_APP_NOTIFY_TEMPLATE_ID = "K0RUbGggwYz7V4yjtJjFVXtthnx4hOJgHvr7RNOyRSE";
    private final IFsStoreOrderCacheServiceImpl fsStoreOrderCacheService;
    private final IFsUserCacheServiceImpl IFsUserCacheService;

    /**
     * 查询定时发放优惠券队列
     *
     * @param id 定时发放优惠券队列ID
     * @return 定时发放优惠券队列
     */
    @Override
    public FsCouponSchedule selectFsCouponScheduleById(Long id)
    {
        return fsCouponScheduleMapper.selectFsCouponScheduleById(id);
    }

    @Override
    public FsCouponSchedule selectFsCouponScheduleByOrderId(String orderId) {
        return fsCouponScheduleMapper.selectFsCouponScheduleByOrderId(orderId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void setScheduleCouponRefund(String orderCode) {
        FsCouponSchedule fsCouponSchedule = fsCouponScheduleMapper.selectFsCouponScheduleByOrderId(orderCode);
        if(ObjectUtil.isNotNull(fsCouponSchedule)){
            fsCouponSchedule.setStatus(IcgProcessStatusEnum.REJECTED_OR_RETURNED.getCode());
            fsCouponScheduleMapper.updateFsCouponSchedule(fsCouponSchedule);
        }
    }

    /**
     * 查询定时发放优惠券队列列表
     *
     * @param fsCouponSchedule 定时发放优惠券队列
     * @return 定时发放优惠券队列
     */
    @Override
    public List<FsCouponSchedule> selectFsCouponScheduleList(FsCouponSchedule fsCouponSchedule)
    {

        if(StringUtils.isNotBlank(fsCouponSchedule.getOrderCode())){
            FsStoreOrder fsStoreOrder = fsStoreOrderCacheService.selectFsStoreOrderByOrderCode(fsCouponSchedule.getOrderCode());
            if(ObjectUtil.isNotNull(fsStoreOrder)){
                fsCouponSchedule.setOrderId(fsStoreOrder.getId());
            } else {
                fsCouponSchedule.setOrderId(-1L);
            }
        }
        List<FsCouponSchedule> list = fsCouponScheduleMapper.selectFsCouponScheduleList(fsCouponSchedule);

        for (FsCouponSchedule couponSchedule : list) {
            if(ObjectUtil.isNotNull(couponSchedule.getOrderId())){
                FsStoreOrder fsStoreOrder = fsStoreOrderCacheService.selectFsStoreOrderById(couponSchedule.getOrderId());
                if(ObjectUtil.isNotNull(fsStoreOrder)){
                    couponSchedule.setOrderCode(fsStoreOrder.getOrderCode());
                    couponSchedule.setUserName(fsStoreOrder.getRealName());
                }
            }
        }
        return list;
    }

    /**
     * 新增定时发放优惠券队列
     *
     * @param fsCouponSchedule 定时发放优惠券队列
     * @return 结果
     */
    @Override
    public int insertFsCouponSchedule(FsCouponSchedule fsCouponSchedule)
    {
        fsCouponSchedule.setCreateTime(DateUtils.getNowDate());
        return fsCouponScheduleMapper.insertFsCouponSchedule(fsCouponSchedule);
    }

    /**
     * 修改定时发放优惠券队列
     *
     * @param fsCouponSchedule 定时发放优惠券队列
     * @return 结果
     */
    @Override
    public int updateFsCouponSchedule(FsCouponSchedule fsCouponSchedule)
    {
        fsCouponSchedule.setUpdateTime(DateUtils.getNowDate());
        return fsCouponScheduleMapper.updateFsCouponSchedule(fsCouponSchedule);
    }

    /**
     * 批量删除定时发放优惠券队列
     *
     * @param ids 需要删除的定时发放优惠券队列ID
     * @return 结果
     */
    @Override
    public int deleteFsCouponScheduleByIds(Long[] ids)
    {
        return fsCouponScheduleMapper.deleteFsCouponScheduleByIds(ids);
    }

    /**
     * 删除定时发放优惠券队列信息
     *
     * @param id 定时发放优惠券队列ID
     * @return 结果
     */
    @Override
    public int deleteFsCouponScheduleById(Long id)
    {
        return fsCouponScheduleMapper.deleteFsCouponScheduleById(id);
    }

    /**
     * 发放优惠券
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void issueCoupon() {
        List<FsCouponSchedule> fsCouponSchedules = fsCouponScheduleMapper.selectPendingCouponList();
        List<FsCouponScheduleLog> logList = new ArrayList<>();
        List<FsMiniprogramSubNotifyTask> subNotifyTasks = new ArrayList<>();

        for (FsCouponSchedule fsCouponSchedule : fsCouponSchedules) {

            FsCouponScheduleLog scheduleLog = new FsCouponScheduleLog();

            scheduleLog.setScheduleId(fsCouponSchedule.getId());
            scheduleLog.setOrderId(fsCouponSchedule.getOrderId());
            scheduleLog.setUserId(fsCouponSchedule.getUserId());
            scheduleLog.setStatusBefore(fsCouponSchedule.getStatus());
            scheduleLog.setSendTimeBefore(fsCouponSchedule.getSendTime());
            scheduleLog.setRetryCountBefore(fsCouponSchedule.getRetryCount());
            scheduleLog.setOperator("SYSTEM");
            scheduleLog.setOperationTime(LocalDateTime.now());
            // 获取优惠券名称
            Set<Long> couponIds = fsCouponSchedule.getCouponId();
            if(CollectionUtils.isEmpty(couponIds)){
                log.info("当前优惠券没有被选择!已经跳过");
                continue;
            }
            // 优惠券id (有多张这里只取第一张)
            Long couponId = couponIds.stream().findFirst().get();
            // 找到该优惠券
            FsStoreCouponIssue fsStoreCouponIssue = fsStoreCouponIssueService.selectFsStoreCouponIssueByCouponId(couponId);
            Long userId = fsCouponSchedule.getUserId();
            // 领取优惠券
            FsStoreCouponReceiveParam param = new FsStoreCouponReceiveParam();
            param.setId(fsStoreCouponIssue.getId());
            R receive = fsStoreCouponIssueService.receiveMonthOnce(String.valueOf(userId), param);

            Set<String> operationTypeSet = new HashSet<>();
            if(fsCouponSchedule.getRetryCount()>0) {
                operationTypeSet.add(IcgScheduleOperationTypeEnum.RETRY.getCode());
            }
            // 如果不等于200表示失败了
            if(ObjectUtil.notEqual(200,receive.get("code"))){
                fsCouponSchedule.setErrorMessage(JSON.toJSONString(receive));
                fsCouponSchedule.setStatus(IcgProcessStatusEnum.FAILED.getCode());
                fsCouponSchedule.setRetryCount(fsCouponSchedule.getRetryCount()+1);

                scheduleLog.setStatusAfter(IcgProcessStatusEnum.FAILED.getCode());
                scheduleLog.setErrorMessage(fsCouponSchedule.getErrorMessage());

                operationTypeSet.add(IcgScheduleOperationTypeEnum.ERROR.getCode());
            } else {
                if(fsCouponSchedule.getCount() >=  fsCouponSchedule.getMonth()){
                    fsCouponSchedule.setStatus(IcgProcessStatusEnum.FINISHED.getCode());
                } else {
                    fsCouponSchedule.setStatus(IcgProcessStatusEnum.SUCCESS.getCode());
                }
                fsCouponSchedule.setActualSendTime(LocalDateTime.now());
                fsCouponSchedule.setSendTime(fsCouponSchedule.getActualSendTime().plusMonths(1).withDayOfMonth(10));
                fsCouponSchedule.setCount(fsCouponSchedule.getCount()+1);
                // 清空错误信息
                fsCouponSchedule.setErrorMessage(null);
                scheduleLog.setStatusAfter(IcgProcessStatusEnum.SUCCESS.getCode());
                scheduleLog.setActualSendTime(fsCouponSchedule.getActualSendTime());
                scheduleLog.setSendTimeAfter(fsCouponSchedule.getSendTime());
                operationTypeSet.add(IcgScheduleOperationTypeEnum.NORMAL.getCode());


                // 小程序消息通知
                FsMiniprogramSubNotifyTask notifyTask = new FsMiniprogramSubNotifyTask();
                notifyTask.setTaskName(WX_MINI_APP_NOTIFY_TASK_NAME);
                notifyTask.setTemplateId(WX_MINI_APP_NOTIFY_TEMPLATE_ID);
                FsUser fsUser = fsUserMapper.selectFsUserById(fsCouponSchedule.getUserId());
                String maOpenId = fsUser.getMaOpenId();
                notifyTask.setTouser(maOpenId);
                notifyTask.setPage(fsCouponSchedule.getPage());

                notifyTask.setCreateTime(LocalDateTime.now());
                // 状态等待执行
                notifyTask.setStatus(MiniAppNotifyTaskStatusEnum.WAITING.getValue());
                notifyTask.setRetryCount(0);
                notifyTask.setMaxRetries(3);
                notifyTask.setUpdateTime(LocalDateTime.now());
                Map<String, TemplateMessageSendRequestDTO.TemplateDataValue> data = new HashMap<>();


                TemplateMessageSendRequestDTO.TemplateDataValue couponName = new TemplateMessageSendRequestDTO.TemplateDataValue();
                FsStoreCoupon fsStoreCoupon = fsStoreCouponMapper.selectFsStoreCouponById(couponId);
                if(ObjectUtil.isNotNull(fsStoreCoupon)){
                    String couponNameById = fsStoreCoupon.getTitle();
                    if(StringUtil.isNotEmpty(couponNameById)){
                        couponName.setValue(String.format("%s 已下发账户,请及时使用!",couponNameById));
                    }
                }

                // 获取优惠券时间范围
                TemplateMessageSendRequestDTO.TemplateDataValue couponValidate = new TemplateMessageSendRequestDTO.TemplateDataValue();


                if(ObjectUtil.isNotNull(fsStoreCouponIssue)){
                    Date beginTime = fsStoreCouponIssue.getStartTime();
                    Date endTime = fsStoreCouponIssue.getLimitTime();
                    String beginTimeStr = DateUtil.format(beginTime, "yyyy-MM-dd");
                    String endTimeStr = DateUtil.format(endTime, "yyyy-MM-dd");

                    if(StringUtil.isNotEmpty(beginTimeStr) && StringUtil.isNotEmpty(endTimeStr)){
                        couponValidate.setValue(beginTimeStr + " ~ " + endTimeStr);
                    } else {
                        couponValidate.setValue("#");
                    }
                }
                // 备注消息
                TemplateMessageSendRequestDTO.TemplateDataValue couponMark = new TemplateMessageSendRequestDTO.TemplateDataValue();
                couponMark.setValue(fsCouponSchedule.getRemark());

                // 面值
                TemplateMessageSendRequestDTO.TemplateDataValue couponPrice = new TemplateMessageSendRequestDTO.TemplateDataValue();
                if(ObjectUtil.isNotNull(fsStoreCoupon)){
                    if(ObjectUtil.isNotNull(fsStoreCoupon.getCouponPrice())){
                        couponPrice.setValue(fsStoreCoupon.getCouponPrice().toPlainString());
                    }
                }

//                data.put("thing1",couponName);
//                data.put("time2",couponValidate);
//                data.put("thing3",couponMark);
//                data.put("amount4",couponPrice);

                data.put("thing1",couponName);
                data.put("thing6",couponMark);

                notifyTask.setData(JSON.toJSONString(data));

                subNotifyTasks.add(notifyTask);
            }
            fsCouponSchedule.setUpdateTime(new Date());

            scheduleLog.setOperationType(String.join(",",operationTypeSet));
            logList.add(scheduleLog);
        }
        // 批量更新发放优惠券队列表
        if(CollectionUtils.isNotEmpty(fsCouponSchedules)){
            fsCouponScheduleMapper.updateBatchFsCouponSchedule(fsCouponSchedules);
        }
        // 批量添加执行日志
        if(CollectionUtils.isNotEmpty(logList)){
            fsCouponScheduleLogMapper.batchInsert(logList);
        }
        // 批量进行微信公众号消息通知
        if(CollectionUtils.isNotEmpty(subNotifyTasks)){
            fsMiniprogramSubNotifyTaskMapper.insertBatch(subNotifyTasks);
        }
    }
}
