package com.cyksj.service.scheduler.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.constant.Constant;
import com.cyksj.common.util.StringUtil;
import com.cyksj.dto.RedisKey;
import com.cyksj.mapper.*;
import com.cyksj.model.entity.*;
import com.cyksj.model.manage.views.GroupsRelationView;
import com.cyksj.model.request.ChangeRelationReq;
import com.cyksj.redis.RedisService;
import com.cyksj.service.error.UserRelationChangeErrorRecordService;
import com.cyksj.service.groups.GroupsFuncService;
import com.cyksj.service.mange.CmsOrderDonService;
import com.cyksj.service.order.OrderRefundService;
import com.cyksj.service.relation.GroupRelationClearService;
import com.cyksj.service.scheduler.SchedulerService;
import com.cyksj.service.user.UserBenefitsService;
import com.ejlchina.searcher.BeanSearcher;
import com.ejlchina.searcher.param.Operator;
import com.ejlchina.searcher.util.MapUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/*
 *项目名: netflix
 *文件名: SchedulerServiceImpl
 *创建者: JavaZou
 *创建时间:2023/6/8 16:48
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SchedulerServiceImpl implements SchedulerService {

	private final GoodsDonSkuMapper skuMapper;

	private final GroupsMapper groupsMapper;

	private final BeanSearcher beanSearcher;

	private final OrderDonMapper orderDonMapper;

	private final GroupsRelationMapper groupsRelationMapper;

	private final GroupRelationClearService groupRelationClearService;

	private final UserBenefitsService userBenefitsService;

	private final GroupsFuncService groupsFuncService;

	private final OrderRefundService orderRefundService;

	private final CmsOrderDonService cmsOrderDonService;

	private final UserRelationChangeErrorRecordService changeErrorRecordService;

	private final UserRelationChangeErrorRecordMapper userRelationChangeErrorRecordMapper;

	private final GoodsDonMapper goodsDonMapper;

	private final RedisService redisService;

	@Override
	public void transExpiryAccountValidRelation() {
		DateTime now = new DateTime();
		DateTime nextBeginDay = DateUtil.offsetDay(DateUtil.beginOfDay(now), 1);
		//针对AI类 CHAT PLUS、MidJourney 月付
		List<Long> aiSkuIds = skuMapper.selectAIMonthSkuIds(Constant.AI_goodsIds);
		List<GroupsTrips> expiryAccountGroups = groupsMapper.getExpiryAccountGroups(nextBeginDay, aiSkuIds);
		expiryAccountGroups.forEach(expiry_groups -> {
			if (expiry_groups.getStatus() != GroupsTrips.Status.down) {
				expiry_groups.setStatus(GroupsTrips.Status.down);
				groupsMapper.updateById(expiry_groups);
			}
			Long g_groupsId = expiry_groups.getId();
			Date a_expiryTime = expiry_groups.getExpiryTime();
			//未过期用户 只分配有效的用户车票 outside状态过滤
			List<GroupsRelationView> groupsRelations = beanSearcher.searchAll(GroupsRelationView.class, MapUtils.builder()
					.field(GroupsRelationView::getGroupsId, g_groupsId)
					.field(GroupsRelationView::getStatus, GroupsRelation.Status.validity.name())
					.field(GroupsRelationView::getExpiryTime, nextBeginDay).op(Operator.GreaterEqual)
					.build());
			reAssign(g_groupsId, now, groupsRelations, UserTicketClearedRecord.Source.timing_change_ticket);
		});
	}

	@Override
	public void assignUserGroupsRelation(Long groupsId) {
		GroupsTrips groupsTrips = groupsMapper.selectById(groupsId);
		if (groupsTrips == null || groupsTrips.getAccountId() == null) return;
		String key = RedisKey.DISABLE_ACCOUNT_ASSIGN + groupsId;
		if (!redisService.setNx(key, groupsId, 60 * 3l)) {
			return;
		}
		if (groupsTrips.getStatus() != GroupsTrips.Status.down) {
			groupsTrips.setStatus(GroupsTrips.Status.down);
			groupsMapper.updateById(groupsTrips);
		}
		DateTime now = DateTime.now();
		//迁移用户
		List<GroupsRelationView> groupsRelations = beanSearcher.searchAll(GroupsRelationView.class, MapUtils.builder()
				.field(GroupsRelationView::getGroupsId, groupsId)
				.field(GroupsRelationView::getStatus, List.of(GroupsRelation.Status.validity.name(), GroupsRelation.Status.outside.name())).op(Operator.InList)
				.field(GroupsRelationView::getExpiryTime, now).op(Operator.GreaterEqual)
				.build());
		reAssign(groupsId, now, groupsRelations, UserTicketClearedRecord.Source.disable);
		redisService.del(key);
	}

	/**
	 * 重新分配车位
	 */
	public void reAssign(Long g_groupsId, DateTime now, List<GroupsRelationView> groupsRelations, UserTicketClearedRecord.Source source) {
		log.info("迁移groupsId:{}未过期用户数量:{}", g_groupsId, groupsRelations.size());
		Map<Long, GoodsDon> goodsMap = new ConcurrentHashMap<>();
		Map<Long, GoodsDonSku> skuMap = new ConcurrentHashMap<>();
		groupsRelations.forEach(relationView -> {
			Long change_relationId = relationView.getId();
			Long userId = relationView.getUserId();
			UserRelationChangeErrorRecord exists = userRelationChangeErrorRecordMapper.selectOne(Wrappers.lambdaQuery(UserRelationChangeErrorRecord.class)
					.eq(UserRelationChangeErrorRecord::getRelationId, change_relationId)
					.eq(UserRelationChangeErrorRecord::getUserId, userId)
					.eq(UserRelationChangeErrorRecord::getDeleted, true)
					.last("limit 1"));
			if (exists != null) {
				log.info("存在userId:{}无法转移的车票relationId:{}", userId, change_relationId);
				return;
			}
			Date expiryTime = DateUtil.beginOfDay(relationView.getExpiryTime());
			Long skuId = relationView.getSkuId();
			//仅针对chatGPT
			if (Constant.AI_goodsIds.contains(relationView.getGoodsId())) {
				Long bet_day = DateUtil.between(now, expiryTime, DateUnit.DAY);
				//10人月付 10天内硬塞20个 10天外硬塞10个
				//4人月付 硬塞5个
				Integer extra_num = 5;
				//10天以内
				if (bet_day <= 10) {
					if (skuId.equals(161l)) {
						extra_num = 20;
					}
					//分配到过期账号5天内误差的相同规格车队里
					DateTime five_day = DateUtil.offsetDay(expiryTime, 5);
					Long item_groupsId = groupsMapper.selectSameSpecItemGroupsByTime(g_groupsId, skuId, expiryTime, five_day, extra_num);
					if (item_groupsId == null) {
						//无对应车队 退款
						//退款至余额
						OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
								.eq(OrderDon::getRelationId, change_relationId)
								.eq(OrderDon::getUserId, userId)
								.notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
								.orderByDesc(OrderDon::getId)
								.last("limit 1"));
						if (orderDon == null) {
							//更换过车票
							orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class)
									.eq(OrderDon::getSkuId, skuId)
									.eq(OrderDon::getUserId, userId)
									.notIn(OrderDon::getStatus, Constant.noOrderAllStatus)
									.orderByDesc(OrderDon::getId)
									.last("limit 1"));
						}
						if (orderDon == null) {
							log.error("用户userId:{}的车票relationId:{}账号过期后转移错误", userId, change_relationId);
							changeErrorRecordService.changeTicketErrorRecord(relationView, UserRelationChangeErrorRecord.Source.change);
							return;
						}
						//清除车票
						GroupsRelation relation = groupsRelationMapper.selectById(change_relationId);
						groupRelationClearService.clearTicket(relation, UserTicketClearedRecord.Source.refund_balance);
						//退款至余额
						//实付金额 + 余额
						BigDecimal money = orderDon.getMoney().add(orderDon.getBalance());
						//当月天数
						Date payTime = orderDon.getPayTime();
						if (payTime == null) {
							payTime = orderDon.getCreatedTime();
						}
						if (money.compareTo(BigDecimal.ZERO) == 0) {
							GoodsDonSku sku = skuMapper.selectById(skuId);
							if (sku != null) {
								money = sku.getPrice();
							}
						}
						int dayNum = DateUtil.dayOfMonth(DateUtil.endOfMonth(payTime));
						BigDecimal re_balance = money.divide(BigDecimal.valueOf(dayNum), 0, RoundingMode.DOWN).multiply(BigDecimal.valueOf(bet_day));
						if (re_balance.compareTo(BigDecimal.ZERO) <= 0) {
							log.info("user_id:{},relationId:{}返回余额为0", userId, change_relationId);
							return;
						}
						GoodsDon goodsDon = goodsMap.get(relationView.getGoodsId());
						if (goodsDon == null) {
							goodsDon = goodsDonMapper.selectById(relationView.getGoodsId());
							if (goodsDon == null) return;
							goodsMap.putIfAbsent(relationView.getGoodsId(), goodsDon);
						}
						userBenefitsService.addUserBalance(userId, re_balance, UserBalanceSourceRecord.Source.clear_valid, relationView.getYhsId(), orderDon.getId(), goodsDon.getTitle() + UserBalanceSourceRecord.Source.clear_valid.getDesc(), true);
						log.info("车票未到期清除,退款至用户user_id:{}余额:{}成功", userId, re_balance);
						//修改订单状态 为退款
						orderDon.setStatus(OrderDon.Status.refund);
						orderDon.setRefundBalance(re_balance);
						orderDon.setRefundMoney(BigDecimal.ZERO);
						orderDonMapper.updateById(orderDon);
						GoodsDonSku sku = skuMap.get(orderDon.getSkuId());
						if (sku == null) {
							sku = skuMapper.selectById(orderDon.getSkuId());
							if (sku == null) return;
							skuMap.putIfAbsent(orderDon.getSkuId(), sku);
						}
						orderRefundService.refundRecord(orderDon, orderDon.getRefundMoney(), null, null, goodsDon, sku, StrUtil.EMPTY, "balance", null);
						return;
					}
					changeTickerRelation(item_groupsId, relationView, source, relationView.getYhsId());
					return;
				}
				//大于10天
				//分配到过期账号10天内误差的相同规格车队里
				if (skuId.equals(161l)) {
					extra_num = 10;
				}
				DateTime ten_day = DateUtil.offsetDay(expiryTime, 10);
				Long item_groupsId = groupsMapper.selectSameSpecItemGroupsByTime(g_groupsId, skuId, expiryTime, ten_day, extra_num);
				if (item_groupsId == null) {
					//无对应车队 生成空车队
					//寻找空车队
					item_groupsId = groupsMapper.selectSameSpecEmptyGroups(skuId);
					if (item_groupsId == null) {
						//新增空车队
						GoodsDonSku sku = skuMapper.selectById(skuId);
						GroupsRelation new_relation = groupsFuncService.createNewGroupsTrips(sku);
						item_groupsId = new_relation.getGroupsId();
					}
					//新车队
					changeTickerRelation(item_groupsId, relationView, UserTicketClearedRecord.Source.new_groups_ticket, relationView.getYhsId());
					return;
				}
				changeTickerRelation(item_groupsId, relationView, source, relationView.getYhsId());
				return;
			}
		});
	}

	public void changeTickerRelation(Long item_groupsId, GroupsRelationView relationView, UserTicketClearedRecord.Source source, Long yhsId) {
		Long change_relationId = relationView.getId();
		try {
			ChangeRelationReq req = new ChangeRelationReq();
			req.setGroupsId(item_groupsId);
			req.setRelationId(change_relationId);
			req.setSource(source);
			req.setIsOutside(true);
			req.setYhsId(yhsId);
			cmsOrderDonService.changeRelation(req);
		} catch (Exception e) {
			log.error("更换用户relationId:{}错误:{}", change_relationId, StringUtil.getErrorText(e));
			relationView.setErrorMsg(StringUtil.getErrorMsg(e));
			changeErrorRecordService.changeTicketErrorRecord(relationView, UserRelationChangeErrorRecord.Source.change);
		}
	}
}
