package com.kxs.product.biz.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.crypto.symmetric.AES;
import com.alibaba.fastjson.JSON;
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.kxs.common.core.constant.SecurityConstants;
import com.kxs.common.core.constant.enums.ErrorTypeEnum;
import com.kxs.common.core.exception.GlobalCustomerException;
import com.kxs.common.core.util.R;
import com.kxs.common.core.util.RetOps;
import com.kxs.common.security.util.SecurityUtils;
import com.kxs.product.api.dto.kxsapp.machine.*;
import com.kxs.product.api.model.*;
import com.kxs.product.api.vo.kxsapp.machine.*;
import com.kxs.common.core.constant.enums.MachineTypeEnum;
import com.kxs.product.biz.constant.enums.ProductErrorTypeEnum;
import com.kxs.product.biz.mapper.*;
import com.kxs.product.biz.service.KxsMachineService;
import com.kxs.store.api.feign.RemoteKxsStoreService;
import com.kxs.system.api.feign.RemoteOldService;
import com.kxs.system.api.vo.kxsapp.RecycleBrandListVO;
import com.kxs.user.api.feign.RemoteKxsUserService;
import com.kxs.user.api.model.KxsUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 客小爽机具表(KxsMachine)表服务实现类
 *
 * @author 系统
 * @since 2023-12-20 10:09:35
 */
@Service("kxsMachineService")
@RequiredArgsConstructor
@Slf4j
public class KxsMachineServiceImpl extends ServiceImpl<KxsMachineMapper, KxsMachine> implements KxsMachineService {

    private final KxsBrandMapper kxsBrandMapper;

    private final KxsMachineTrackMapper kxsMachineTrackMapper;

    private final KxsMachineTransferMapper kxsMachineTransferMapper;

    private final KxsMachineDeductMapper kxsMachineDeductMapper;

    private final RemoteKxsUserService remoteKxsUserService;

    private final RemoteKxsStoreService remoteKxsStoreService;

    private final RemoteOldService remoteOldService;

    private final AES cryptoOldAes;

    @Override
    public IPage<MachineStoreListVO> machineStoreList(Page<MachineStoreListVO> page, MachineStoreListDTO param) {

        return baseMapper.machineStoreList(page, param);
    }

    @Override
    public IPage<MachineStoreListVO> searchStoreMachine(Page<MachineStoreListVO> page, MachineStoreListDTO param) {

        return baseMapper.machineStoreList(page, param);
    }

    @Override
    public IPage<RecycleMachinesVO> recycleMachinesPage(Page<RecycleMachinesVO> page, Integer brandType) {

        Long userId = SecurityUtils.getUser().getId();

        //查询品牌
        List<KxsBrand> brands = kxsBrandMapper.selectList(Wrappers.<KxsBrand>lambdaQuery().eq(KxsBrand::getBrandType, brandType));
        List<Integer> brandIds = brands.stream().map(KxsBrand::getId).toList();

        IPage<RecycleMachinesVO> recycleMachines = baseMapper.recycleMachinesPage(page, userId, brandIds);

        recycleMachines.getRecords().forEach(item -> item.setBrandList(brandIds));

        return recycleMachines;
    }

    @Override
    public IPage<MachineUnBindListVO> machineUnBindListPage(Page<MachineUnBindListVO> page, MachineUserListDTO param) {

        param.setUserId(SecurityUtils.getUser().getId().intValue());

        return baseMapper.machineUnBindListPage(page, param);
    }

    @Override
    public IPage<MachineBindListVO> machineBindList(Page<MachineBindListVO> page, MachineUserListDTO param) {

        param.setUserId(SecurityUtils.getUser().getId().intValue());

        return baseMapper.machineBindList(page, param);
    }

    @Override
    public IPage<MachineUserListVO> getByPage(Page<MachineUserListVO> page, MachineUserListDTO param) {

        param.setUserId(SecurityUtils.getUser().getId().intValue());

        return baseMapper.getByPage(page, param);
    }

    @Override
    public MachineApplyRemarkVO applyRemark() {

        Integer userId = SecurityUtils.getUser().getId().intValue();

        //兑换机 激活数量
        Long actCount = baseMapper.selectCount(Wrappers.<KxsMachine>lambdaQuery()
                .eq(KxsMachine::getUserId, userId)
                .eq(KxsMachine::getMachineType, MachineTypeEnum.M_TYPE_SN.getType())
                .eq(KxsMachine::getIsAct, MachineTypeEnum.ACT.getType()));

        //过期的循环机数量,兑换机循环时间结束
        Long pastCount = baseMapper.selectCount(Wrappers.<KxsMachine>lambdaQuery()
                .eq(KxsMachine::getUserId, userId)
                .eq(KxsMachine::getMachineType, MachineTypeEnum.M_TYPE_SN.getType())
                .lt(KxsMachine::getRecycleEndTime, LocalDateTime.now()));

        return MachineApplyRemarkVO.builder()
                .actCount(actCount)
                .pastCount(pastCount)
                .maxCount(actCount - pastCount)
                .minCount(actCount - pastCount > 0 ? 1 : 0)
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R machineTransferUser(MachineTransferDTO param) {

        Integer userId = SecurityUtils.getUser().getId().intValue();

        R<KxsUser> kxsUserR = remoteKxsUserService.loadUserByCode(param.getUserCode(), SecurityConstants.FROM_IN);
        KxsUser toUser = RetOps.of(kxsUserR)
                .getData()
                .orElseThrow(() -> new GlobalCustomerException(ErrorTypeEnum.USER_NOT_FOUND.getDescription()));

        R<Boolean> booleanR = remoteKxsUserService.checkUserIsChildren(userId, toUser.getId(), SecurityConstants.FROM_IN);
        if (!booleanR.getData()) {
            return R.failed(ProductErrorTypeEnum.USER_IS_NOT_FIND.getDescription());
        }

        for (String sn : param.getSnList()) {
            KxsMachine machine = baseMapper.selectOne(Wrappers.<KxsMachine>lambdaQuery()
                    .eq(KxsMachine::getUserId, userId)
                    .eq(KxsMachine::getPosSn, sn));
            if (machine == null) {
                throw new GlobalCustomerException(sn + ProductErrorTypeEnum.MACHINE_NOT_FOUND.getDescription());
            }
            if (machine.getBindStatus().equals(MachineTypeEnum.BIND.getType())) {
                throw new GlobalCustomerException(sn + ProductErrorTypeEnum.MACHINE_BIND.getDescription());
            }
            if (!machine.getUserId().equals(userId)) {
                throw new GlobalCustomerException(sn + ProductErrorTypeEnum.MACHINE_NOT_USER.getDescription());
            }
            //循环机不可划拨
            if (machine.getMachineType().equals(MachineTypeEnum.M_TYPE_RE.getType())) {
                throw new GlobalCustomerException(sn + ProductErrorTypeEnum.MACHINE_TRANSFER_NO.getDescription());
            }
            //机具轨迹路径
            String allotPath = machine.getAllotPath() == null ? "0," : machine.getAllotPath();
            machine.setAllotPath(allotPath + machine.getUserId() + ",");
            machine.setUserId(toUser.getId());
            //修改机具所属
            baseMapper.updateById(machine);

            //添加机具划拨记录
            KxsMachineTransfer machineTransfer = new KxsMachineTransfer();
            //拨出用户
            machineTransfer.setSendUserId(userId);
            //拨入用户
            machineTransfer.setToUserId(toUser.getId());
            machineTransfer.setToUserName(toUser.getUsername());
            machineTransfer.setToUserCode(toUser.getUserCode());
            machineTransfer.setMachineSn(machine.getPosSn());
            machineTransfer.setMachineId(machine.getId());
            machineTransfer.setBrandId(machine.getBrandId());
            kxsMachineTransferMapper.insert(machineTransfer);

        }

        return R.ok();
    }

    @Override
    public IPage<SearchUserMachineVO> searchUserMachine(Page<SearchUserMachineVO> page, SearchUserMachineDTO param) {

        param.setUserId(SecurityUtils.getUser().getId().intValue());

        return baseMapper.searchUserMachine(page, param);
    }

    @Override
    public IPage<MachineRecycleListVO> recycleList(Page<MachineRecycleListVO> page, RecycleMachineQuery param) {

        Long userId = SecurityUtils.getUser().getId();
        param.setUserId(userId.intValue());

        return baseMapper.recyclePageList(page, param);
    }

    @Override
    public IPage<StoreActMachineMonthTotalVO> activateMachineMonthTotal(Page<StoreActMachineMonthTotalVO> page, StoreActMachineMonthTotalDTO param) {

        return baseMapper.activateMachineMonthTotal(page, param);
    }

    @Override
    public IPage<StoreActMachineDayDetailVO> activateMachineMonthTotalDetail(Page<StoreActMachineDayDetailVO> page, StoreActMachineDayDetailDTO param) {

        String month = param.getMonth() + "-01";
        //根据月份获取本月开始时间和结束时间
        LocalDate date = LocalDate.parse(month, DatePattern.NORM_DATE_FORMATTER);
        LocalDateTime startTime = LocalDateTime.of(date, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(date.plusMonths(1), LocalTime.MIN);

        param.setStartDate(String.valueOf(startTime));
        param.setEndDate(String.valueOf(endTime));

        return baseMapper.activateMachineMonthTotalDetail(page, param);
    }

    @Override
    public List<ExpiredModalBrandVO> expiredModal() {
        Long userId = SecurityUtils.getUser().getId();
        // 开始时间
//        long stime = System.currentTimeMillis();

        List<ExpiredModalBrandVO> result = new ArrayList<>();
        //查询用户已经申请了回收的机具
        R<List<String>> listR = remoteKxsStoreService.recycleSnList(SecurityConstants.FROM_IN);
        List<String> sns = RetOps.of(listR)
                .getData()
                .orElse(new ArrayList<>());
        //查询品牌
        List<KxsBrand> brands = kxsBrandMapper.selectList(Wrappers.emptyWrapper());
        //转map方便查询
        Map<Integer, KxsBrand> brandMap = brands.stream().collect(Collectors.toMap(KxsBrand::getId, Function.identity()));

        /*
            查询思路
            获取昨天的开始时间
            所有循环机 and 未绑定 and 循环结束时间小于于昨天的开始时间 and 用户ID
         */
        LocalDateTime startDay = LocalDate.now().plusDays(1).atStartOfDay();
        //TODO 暂时取消30天内的限制
        LocalDateTime endDay = LocalDate.now().minusDays(29).atStartOfDay();

        KxsMachine machineQuery = new KxsMachine();
        machineQuery.setUserId(userId.intValue());
        machineQuery.setBindStatus(MachineTypeEnum.NO_BIND.getType());
        machineQuery.setStatus(MachineTypeEnum.STATUS_OUT.getType());
        machineQuery.setRecycleEndTime(startDay);
        List<KxsMachine> machines = baseMapper.selectDeductList(machineQuery, endDay);


        //过滤已申请回收的机具
        machines = machines.stream().filter(machine -> !sns.contains(machine.getPosSn())).toList();
        //组装数据
        Map<Integer, List<KxsMachine>> groupMachine = machines.stream().collect(Collectors.groupingBy(KxsMachine::getBrandId));
        groupMachine.keySet().forEach(brandId -> {
            KxsBrand kxsBrand = brandMap.get(brandId);
            if (kxsBrand != null) {
                List<KxsMachine> kxsMachines = groupMachine.get(brandId);
                ExpiredModalBrandVO expiredModalBrandVO = new ExpiredModalBrandVO();
                expiredModalBrandVO.setBrandName(kxsBrand.getName());
                //转换为返回的格式
                List<ExpiredModalVO> list = kxsMachines.stream().map(item -> {
                    ExpiredModalVO expiredModalVO = new ExpiredModalVO();
                    expiredModalVO.setPosSn(item.getPosSn());
                    Duration between = LocalDateTimeUtil.between(item.getRecycleEndTime(), LocalDateTime.now());

                    expiredModalVO.setExpiredDay(between.toDays());
                    return expiredModalVO;
                }).toList();
                expiredModalBrandVO.setList(list);
                result.add(expiredModalBrandVO);
            }
        });
        // 结束时间
        long etime1 = System.currentTimeMillis();
        // 计算执行时间
//        System.out.printf("执行时长：%d 毫秒.", (etime - stime));
//        System.out.printf("执行时长：%d 毫秒.", (etime1 - stime));
        return result;
    }

    @Override
    @Async("getAsyncExecutor")
    public void recycleMachineSchedule(String para) {
        LocalDateTime endDay = LocalDate.now().minusDays(15).atStartOfDay();
        List<KxsMachine> machines = baseMapper.selectExpireDeductList(endDay);

        for (KxsMachine machine : machines) {
            HashMap<String, Object> param = new HashMap<>();
            HashMap<String, Object> data = new HashMap<>();
            data.put("PosSn", machine.getPosSn());
//            String body  = cryptoOldAes.encryptHex(JSON.toJSONString(data));
            param.put("value", JSON.toJSONString(data));
            R result = remoteOldService.savePosAdvance(param);
            if(result.getStatus() == 1){
                log.info("已添加机具到预扣款：{}", machine.getPosSn());

                KxsMachineDeduct machineDeduct = new KxsMachineDeduct();
                machineDeduct.setPosSn(machine.getPosSn());
                machineDeduct.setRemark("已添加预扣款");
                kxsMachineDeductMapper.insert(machineDeduct);
            }else{
                log.info("添加机具到预扣款失败：{}", machine.getPosSn());
            }
        }
    }

    @Override
    public Object recycleBrandList() {
        Long userId = SecurityUtils.getUser().getId();
        return baseMapper.recycleBrandList(userId);
    }


}

