package com.td.WaDa.game.complayercultivate.serivce;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.td.WaDa.common.pojo.CultivateKeys;
import com.td.WaDa.common.pojo.Result;
import com.td.WaDa.common.service.ComConfigService;
import com.td.WaDa.config.enums.ResultEnum;
import com.td.WaDa.game.comconfigland.pojo.ComConfigLand;
import com.td.WaDa.game.comconfigland.service.ComConfigLandService;
import com.td.WaDa.game.comexplainland.service.ComExplainLandService;
import com.td.WaDa.game.comexplainland.vo.ComExplainLandVo;
import com.td.WaDa.game.commallseed.service.ComMallSeedService;
import com.td.WaDa.game.commallseed.vo.ComMallSeedVo;
import com.td.WaDa.game.complayercultivate.pojo.ComPlayerCultivate;
import com.td.WaDa.game.complayercultivate.repository.ComPlayerCultivateRepository;
import com.td.WaDa.game.complayercultivate.vo.ComPlayerCultivateSeedVo;
import com.td.WaDa.game.complayerland.pojo.ComPlayerDisaster;
import com.td.WaDa.game.complayerland.pojo.ComPlayerLand;
import com.td.WaDa.game.complayerland.service.ComPlayerLandService;
import com.td.WaDa.game.complayerland.vo.ComPlayerLandAndPlantVo;
import com.td.WaDa.game.complayerland.vo.ComPlayerLandVo;
import com.td.WaDa.game.comsnbtran.service.ComSnbTranService;
import com.td.WaDa.game.comsnbtran.vo.ComSnbTranVo;
import com.td.WaDa.game.comusers.service.ComUsersService;
import com.td.WaDa.game.comusers.vo.ComUsersVo;
import com.td.WaDa.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

@Service
@Slf4j
@Transactional
public class ComPlayerCultivateSerivceImpl implements ComPlayerCultivateSerivce {

    @Autowired
    private ComMallSeedService comMallSeedService;
    @Autowired
    private ComPlayerLandService comPlayerLandService;
    @Autowired
    private ComExplainLandService comExplainLandService;
    @Autowired
    private ComConfigLandService comConfigLandService;
    @Autowired
    private ComPlayerCultivateRepository cultivateRepository;
    @Autowired
    private ComConfigService comConfigService;
    @Autowired
    private ComUsersService comUsersService;
    @Autowired
    private RedisLock redisLock;

    //交易表service
    @Autowired
    private ComSnbTranService comSnbTranService;

    /**
     * 解锁某个土地 【牧场养殖渔场】
     *
     * @param userId
     * @param configLandId
     * @return
     */
    @Transactional
    @Override
    public Result<?> payLand(String userId, Integer configLandId) {
        //根据土地config id查找，对应ConfigLandId ,
        ComConfigLand comConfigLand = comConfigLandService.findById(configLandId);
        //如果土地等于不能初始化，或者已经种植，不能进行购买
        if (comConfigLand == null || comConfigLand.getIsInit().equals(0)) {
            return Result.of(null, false, ResultEnum.LAND_DATA_ERROR.getMessage(), ResultEnum.LAND_DATA_ERROR.getCode());
        }
        if (ArrayUtil.contains(CultivateKeys.mallType, comConfigLand.getMallType()) == false) {
            return Result.of(null, false, ResultEnum.LAND_DATA_ERROR.getMessage(), ResultEnum.LAND_DATA_ERROR.getCode());
        }
        String _redisKey = "LOCK:COM_PLAYER_CULTIVATE_LAND:" + userId;
        long landTime = System.currentTimeMillis() + RedisData.getLandTimeout();
        try {
            if (!redisLock.lock(_redisKey, String.valueOf(landTime))) {
                log.info("锁住key：" + _redisKey);
                return Result.of(null, false, ResultEnum.REDIS_IS_LOCK.getMessage(), ResultEnum.REDIS_IS_LOCK.getCode());
            }
            ComPlayerLand comPlayerLand = comPlayerLandService.findByUserIdAndLandId(userId, configLandId);
            if (comPlayerLand != null) {
                throw new Exception(ResultEnum.LAND_IS_LEASE.getMessage());
            }
            Integer _getTimes = getTimes(userId);
            if (_getTimes <= 0) {
                throw new Exception(ResultEnum.LAND_NO_TIMES_ERROR.getMessage());
            }
            //创建新土地
            Date nowDate = new Date();
            comPlayerLand = new ComPlayerLand();
            comPlayerLand.setConfigLandId(comConfigLand.getId());
            comPlayerLand.setUserId(userId);
            comPlayerLand.setName(comConfigLand.getName());
            //初始化一下未种植参数
            comPlayerLand.setIsPlant(0);
            comPlayerLand.setCreateTime(nowDate);
            comPlayerLand.setPlantSteal(1);
            comPlayerLand.setMallType(comConfigLand.getMallType());

            comPlayerLand.setLandDescribe("养殖场租赁，每次租赁日期为1个月.");
            comPlayerLand.setLeaseMultiple(getMaxAmount(comConfigLand.getMallType())); // 养殖场倍数,暂时设置最大值
            comPlayerLand.setLeaseDate(4); // 租赁类型改成 4
            //设置租赁日期,定义一个30天日期
            comPlayerLand.setLeaseTime(com.td.WaDa.util.DateUtil.getOldDateAddDay(nowDate, 30));
            //租赁土地
            comPlayerLand.setIsLease(1);
            comPlayerLand.setUpdateTime(nowDate);
            //记录一下租赁费用
            comPlayerLand.setRentalExpenses(1.0d);
            comPlayerLandService.AddComPlayerLand(comPlayerLand);

            Map map = new HashMap();
            map.put("LandInfo", getComPlayerLandAndPlantVo(comPlayerLand));
            map.put("times", _getTimes - 1);
            redisLock.unlock(_redisKey, String.valueOf(landTime));
            return Result.of(map, true, "租赁成功");
        } catch (Exception e) {
            redisLock.unlock(_redisKey, String.valueOf(landTime));
            return ErrorResult(e.getMessage());
        }
    }

    /**
     * 修改某个土地 【牧场养殖渔场】
     *
     * @param userId
     * @param configLandId
     * @param multiple
     * @return
     */
    @Transactional
    @Override
    public Result<?> multipleLand(String userId, Integer configLandId, Integer multiple) {

        //倍数不能为零
        if (multiple <= 0) {
            return Result.of(null, false, ResultEnum.LAND_MULTIPLE_ERROR.getMessage(), ResultEnum.LAND_MULTIPLE_ERROR.getCode());
        }
        ComPlayerLand comPlayerLand = comPlayerLandService.findByUserIdAndLandId(userId, configLandId);
        //只能修改养殖场类型
        if (comPlayerLand == null || ArrayUtil.contains(CultivateKeys.mallType, comPlayerLand.getMallType()) == false) {
            return Result.of(null, false, ResultEnum.LAND_DATA_ERROR.getMessage(), ResultEnum.LAND_DATA_ERROR.getCode());
        }
        //不能超过最大值，倍数
        if (getMaxAmount(comPlayerLand.getMallType()) < multiple) {
            return Result.of(null, false, "最大养殖量：" + getMaxAmount(comPlayerLand.getMallType()), ResultEnum.LAND_MULTIPLE_CONFIG_ERROR.getCode());
        }
        String _redisKey = "LOCK:COM_PLAYER_CULTIVATE_LAND:" + userId;
        long landTime = System.currentTimeMillis() + RedisData.getLandTimeout();
        if (!redisLock.lock(_redisKey, String.valueOf(landTime))) {
            log.info("锁住key：" + _redisKey);
            return ErrorResult("操作频繁！");
        }
        try {
            //修改
            comPlayerLand.setLeaseMultiple(multiple);
            comPlayerLandService.AddComPlayerLand(comPlayerLand);
            redisLock.unlock(_redisKey, String.valueOf(landTime));
            return Result.of(CopyUtil.copy(comPlayerLand, ComPlayerLandVo.class), true, "修改养殖场成功");
        } catch (Exception e) {
            redisLock.unlock(_redisKey, String.valueOf(landTime));
        }
        return ErrorResult("修改养殖场失败！");
    }

    /**
     * 获取租赁机会
     *
     * @param userId
     * @return
     */
    @Override
    public Integer getTimes(String userId) {
        Integer totalcount = DappUtil.getChildrenBuyLandCount(userId);
        long nowcount = comPlayerLandService.findAllByUserId(userId).stream()
                .filter(a -> a.getMallType() != null && ArrayUtil.contains(CultivateKeys.mallType, a.getMallType())).count();
        ComExplainLandVo comExplainLandVo = new ComExplainLandVo();
        comExplainLandVo.setUserId(userId);
        Result<List<ComExplainLandVo>> list = comExplainLandService.list(comExplainLandVo);
        long historycount = list.getData().stream().filter(a -> a.getMallType() != null && ArrayUtil.contains(CultivateKeys.mallType, a.getMallType())).count();
        return totalcount - Convert.toInt(nowcount) - Convert.toInt(historycount);
    }

    /**
     * 喂粮
     *
     * @param userId
     * @param configLandId
     * @return
     */
    @Transactional
    @Override
    public Result<?> buyFood(String userId, Integer configLandId) {
        //获得本次喂的数量
        ComPlayerLand comPlayerLand = comPlayerLandService.findByUserIdAndLandId(userId, configLandId);
        //土地数据不存在
        if (comPlayerLand == null) {
            return Result.of(null, false, ResultEnum.LAND_DATA_ERROR.getMessage(), ResultEnum.LAND_DATA_ERROR.getCode());
        }
        if (!comPlayerLand.getIsLease().equals(1)) {
            return Result.of(null, false, ResultEnum.LAND_NOT_LEASE.getMessage(), ResultEnum.LAND_NOT_LEASE.getCode());
        }
        if (Integer.valueOf(0).equals(comPlayerLand.getMallType())) {
            return Result.of(null, false, ResultEnum.FOOD_NO_TYPE_ERROR.getMessage(), ResultEnum.FOOD_NO_TYPE_ERROR.getCode());
        }
        Integer buyAmount = comPlayerLand.getLeaseMultiple();
        //todo 操作snb数量
        ComUsersVo comUsersVo = comUsersService.findByUserId(userId);
        if (comUsersVo.getSnb() <= 0) {
            return Result.of(null, false, ResultEnum.WALLET_SNB_INSUFFICIENT_QUANTITY.getMessage(), ResultEnum.WALLET_SNB_INSUFFICIENT_QUANTITY.getCode());
        }
        if (Integer.valueOf(0).equals(comPlayerLand.getIsPlant())) {
            return Result.of(null, false, ResultEnum.LAND_NO_PLANT_ERROR.getMessage(), ResultEnum.LAND_NO_PLANT_ERROR.getCode());
        }
        //通过判断土地类型，获取喂粮饲料
        List<ComPlayerCultivateSeedVo> SeedList = comConfigService.selectListByKey(CultivateKeys.cultivateFood, ComPlayerCultivateSeedVo.class);
        ComPlayerCultivateSeedVo seedVo = SeedList.stream().filter(a -> a.getSeedId().equals(comPlayerLand.getMallType())).findFirst().orElse(null);
        if (seedVo == null) {
            return Result.of(null, false, ResultEnum.FOOD_NO_ERROR.getMessage(), ResultEnum.FOOD_NO_ERROR.getCode());
        }
        //判断今天是否已经喂过
        Date begin = DateUtil.beginOfDay(new Date());
        Date end = DateUtil.endOfDay(new Date());
        if (isAnimalEat(userId, comPlayerLand.getMallType(), configLandId, comPlayerLand.getPlantFlag(), begin, end)) {
            return Result.of(null, false, ResultEnum.FOOD_REPEAT_ERROR.getMessage(), ResultEnum.FOOD_REPEAT_ERROR.getCode());
        }
        long time = System.currentTimeMillis() + RedisData.getPlayerCultivateBuyFoodTimeout();
        String _redisKey = "LOCK:COM_PLAYER_CULTIVATE_BUYFOOD:" + userId;
        if (!redisLock.lock(_redisKey, String.valueOf(time))) {
            log.info("锁住key：" + _redisKey);
            return ErrorResult("操作频繁！");
        }
        try {
            ComSnbTranVo _snbTran = new ComSnbTranVo();
            _snbTran.setBeforeSnb(comUsersVo.getSnb());
            _snbTran.setBeforeSnbPart(comUsersVo.getSnbPart());
            //计算
            Double _allSnb = DoubleUtil.add(comUsersVo.getSnb().doubleValue(), comUsersVo.getSnbPart());
            //如果有snb，扣除对应的snb
            Integer _allSnbMaxInt = (int) Math.floor(_allSnb);
            //这个价格需要从配置里取
            double _needPrice = buyAmount * seedVo.getSeedSNB();
            if (_allSnbMaxInt < _needPrice) {
                return Result.of(null, false, ResultEnum.WALLET_SNB_INSUFFICIENT_QUANTITY.getMessage(), ResultEnum.WALLET_SNB_INSUFFICIENT_QUANTITY.getCode());
            }
            double _tranSnb = _allSnbMaxInt - _needPrice;
            comUsersVo.setSnb(Convert.toInt(_tranSnb));
            Double _SnbPart = DoubleUtil.sub(_allSnb, Math.floor(_allSnb));
            comUsersVo.setSnbPart(_SnbPart);
            //记录修改的数据
            comUsersService.save(comUsersVo);

            //持久化喂养记录
            ComPlayerCultivate comPlayerCultivate = new ComPlayerCultivate();
            comPlayerCultivate.setLandId(comPlayerLand.getId());
            comPlayerCultivate.setLandType(comPlayerLand.getMallType());
            comPlayerCultivate.setUserId(userId);
            comPlayerCultivate.setCreateTime(new Date());
            comPlayerCultivate.setConfigLandId(configLandId);
            comPlayerCultivate.setAmount(buyAmount);
            comPlayerCultivate.setActivtyTime(new Date());
            comPlayerCultivate.setSnb(_needPrice);
            comPlayerCultivate.setPlantFlag(comPlayerLand.getPlantFlag());
            cultivateRepository.save(comPlayerCultivate);


            /**
             * 喂养动物时候，记录操作
             */
            ComSnbTranVo snbTran = new ComSnbTranVo();
            snbTran.setTranId(Convert.toStr(seedVo.getSeedId()));
            snbTran.setUserId(userId);
            snbTran.setTranName(StrUtil.format("喂养{}", seedVo.getSeedName()));
            snbTran.setTranType(10);
            snbTran.setTranAmount(buyAmount);
            snbTran.setTranDescribe(StrUtil.format("user喂养动物消耗SNB：{},消耗：{}单价", _needPrice, seedVo.getSeedSNB()));
            snbTran.setIsAdd(0);
            snbTran.setBeforeSnb(_allSnbMaxInt);
            snbTran.setBeforeSnbPart(DoubleUtil.sub(_allSnb, Math.floor(_allSnb)));

            snbTran.setTranSnb((int) Math.floor(_needPrice));
            snbTran.setTranSnbPart(DoubleUtil.sub(_needPrice, Math.floor(_needPrice)));

            snbTran.setAfterSnb(Convert.toInt(_tranSnb));
            snbTran.setAfterSnbPart(_SnbPart);

            snbTran.setCreateTime(new Date());

            snbTran.setTranAmountPart(0d);
            snbTran.setTranPrice(0);
            comSnbTranService.save(snbTran);


            return Result.of(getComPlayerLandAndPlantVo(comPlayerLand), true, "成功");
        } catch (Exception e) {
        } finally {
            redisLock.unlock(_redisKey, String.valueOf(time));
        }
        return ErrorResult("喂养失败！");
    }

    /**
     * 获取成熟时间（计算延期天数），2022年4月7日15:55:11-2022年4月8日15:55:11为一天
     *
     * @param userId
     * @param mallType
     * @param configLandId
     * @param plantFlag
     * @param comMallSeedVo
     * @return
     */
    @Override
    public Integer getHarvestDays(String userId, Date plantStart, Integer mallType, Integer configLandId, String plantFlag, ComMallSeedVo comMallSeedVo) {
        //ComPlayerLand comPlayerLand = comPlayerLandService.findByUserIdAndLandId(userId, configLandId);
        //实际上一共喂几次
        long times = cultivateRepository.countComPlayerCultivateByUserIdAndLandTypeAndConfigLandIdAndPlantFlag(userId, mallType, configLandId, plantFlag);
        //从当天到现在。一共过了几天
        long days = DateUtil.betweenDay(plantStart, new Date(), false);
        long l = 0;
        if (times < days) {
            l = (days - times) * 2;
        }
        return Convert.toInt(l, 0) + comMallSeedVo.getMaturity();
    }

    /**
     * 是否已经喂养
     *
     * @param userId       用户编号
     * @param landType     土地类型 具体是养殖、渔场、放养
     * @param configLandId 土地配置表id
     * @param plantFlag    种植唯一标识
     * @param begin        查询开始时间
     * @param end          查询截止时间
     * @return
     */
    @Override
    public boolean isAnimalEat(String userId, Integer landType, Integer configLandId, String plantFlag, Date begin, Date end) {
        Specification specification = new Specification<ComPlayerDisaster>() {
            @Override
            public Predicate toPredicate(Root<ComPlayerDisaster> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                predicates.add(criteriaBuilder.between(root.get("createTime"), begin, end));
                predicates.add(criteriaBuilder.equal(root.get("userId"), userId));
                predicates.add(criteriaBuilder.equal(root.get("landType"), landType));
                predicates.add(criteriaBuilder.equal(root.get("configLandId"), configLandId));
                predicates.add(criteriaBuilder.equal(root.get("plantFlag"), plantFlag));
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        return cultivateRepository.count(specification) > 0;
    }

    private Result<?> ErrorResult(String msg) {
        return Result.of(null, false, msg);
    }

    /**
     * 获取一个养殖的对象
     *
     * @param comPlayerLand
     * @return
     */
    private ComPlayerLandAndPlantVo getComPlayerLandAndPlantVo(ComPlayerLand comPlayerLand) {

        ComPlayerLandAndPlantVo comPlayerLandAndPlantVo = CopyUtil.copy(comPlayerLand, ComPlayerLandAndPlantVo.class);
        Long leaseDaysMill = comPlayerLandAndPlantVo.getLeaseTime().getTime() - com.td.WaDa.util.DateUtil.getNowDate().getTime();
        Long leaseAllMill = comPlayerLandAndPlantVo.getLeaseTime().getTime() - comPlayerLandAndPlantVo.getCreateTime().getTime();
        Integer allDays = com.td.WaDa.util.DateUtil.getDays(leaseAllMill).intValue() <= 0 ? 0 : com.td.WaDa.util.DateUtil.getDays(leaseAllMill).intValue();
        comPlayerLandAndPlantVo.setLeaseDays(allDays);
        Integer leaseDays = com.td.WaDa.util.DateUtil.getDays(leaseDaysMill).intValue() <= 0 ? 0 : com.td.WaDa.util.DateUtil.getDays(leaseDaysMill).intValue();
        comPlayerLandAndPlantVo.setLeaseDaysRemaining(leaseDays);
        comPlayerLandAndPlantVo.setLeaseDaysMill(leaseDaysMill);
        if (comPlayerLandAndPlantVo.getIsPlant().equals(1)) {
            ComMallSeedVo comMallSeedVo = comMallSeedService.findById(comPlayerLandAndPlantVo.getPlantId());
            //todo [牧场养殖渔场需求] 如果是养殖类的，计算延期后的成熟期
            if (ArrayUtil.contains(CultivateKeys.mallType, comPlayerLandAndPlantVo.getMallType())) {
                Integer days = getHarvestDays(comPlayerLandAndPlantVo.getUserId(), comPlayerLandAndPlantVo.getPlantStart(),comPlayerLandAndPlantVo.getMallType(),comPlayerLandAndPlantVo.getConfigLandId(),comPlayerLandAndPlantVo.getPlantFlag(),comMallSeedVo);
                comMallSeedVo.setMaturity(days);

                //获取并设置今日喂养状态
                Date begin = cn.hutool.core.date.DateUtil.beginOfDay(new Date());
                Date end = cn.hutool.core.date.DateUtil.endOfDay(new Date());
                boolean animalEat = isAnimalEat(comPlayerLandAndPlantVo.getUserId(), comPlayerLandAndPlantVo.getMallType(), comPlayerLandAndPlantVo.getConfigLandId(), comPlayerLandAndPlantVo.getPlantFlag(), begin, end);
                comPlayerLandAndPlantVo.setAnimalEat(animalEat);

                //新加一个养殖的信息
                List<ComPlayerCultivateSeedVo> SeedList = comConfigService.selectListByKey(CultivateKeys.cultivateFood, ComPlayerCultivateSeedVo.class);
                //养殖场部分价格信息
                ComPlayerCultivateSeedVo seedVo = SeedList.stream().filter(a -> a.getSeedId().equals(comPlayerLandAndPlantVo.getMallType())).findFirst().orElse(null);
                comPlayerLandAndPlantVo.setCultivateSeedVo(seedVo);
            }
            comPlayerLandAndPlantVo.setSeedInfo(comMallSeedVo);
            Date _harvestTime = com.td.WaDa.util.DateUtil.getNowDateMinusDay(comMallSeedVo.getMaturity());
            long diff = comPlayerLandAndPlantVo.getPlantStart().getTime() - _harvestTime.getTime();
            comPlayerLandAndPlantVo.setPlantDaysMill(diff);
            if (diff <= 0) {
                //说明可以收获了
                comPlayerLandAndPlantVo.setPlantDaysRemaining(0);
                comPlayerLandAndPlantVo.setPlantHoursRemaining(0);
                //todo [枯萎]
                Integer witheredDay = comConfigService.selectByKey(CultivateKeys.witheredDay, Integer.class);
                if (diff * -1 / CultivateKeys.dayLong > witheredDay) {
                    comPlayerLandAndPlantVo.setWithered(true);
                }
                //这里不触发灾害
            } else {
                comPlayerLandAndPlantVo.setPlantDaysRemaining(com.td.WaDa.util.DateUtil.getDays(diff).intValue());
                comPlayerLandAndPlantVo.setPlantHoursRemaining(com.td.WaDa.util.DateUtil.getHours(diff).intValue());
            }
        } else {
            //未种植时候，设置为0
            comPlayerLandAndPlantVo.setPlantDaysRemaining(0);
            comPlayerLandAndPlantVo.setPlantHoursRemaining(0);
        }

        return comPlayerLandAndPlantVo;
    }

    /**
     * 获取最大种植数量
     *
     * @param mallType
     * @return
     */
    private Integer getMaxAmount(Integer mallType) {
        //获取配置 土堆分别最大种植数量，对应类型mallType：1、2、3、4的值
        List<Map> maps = comConfigService.selectListByKey(CultivateKeys.maxAmount, Map.class);
        return maps.stream().filter(a -> a.get("key").equals(mallType)).map(a -> Convert.toInt(a.get("value"), 0)).findFirst().orElse(10000);
    }
}
