package com.td.Dawa.game.comcharactersdiscovery.service;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import com.td.Dawa.common.pojo.PageInfo;
import com.td.Dawa.common.service.*;
import com.td.Dawa.config.enums.GameEnum;
import com.td.Dawa.config.enums.ResultEnum;
import com.td.Dawa.config.exception.AuthorizeException;
import com.td.Dawa.game.comcharacters.pojo.ComCharacters;
import com.td.Dawa.game.comcharacters.service.ComCharactersService;
import com.td.Dawa.game.comcharacters.vo.ComCharactersClientVo;
import com.td.Dawa.game.comcharacters.vo.ComCharactersVo;
import com.td.Dawa.game.comcharactersdiscovery.pojo.ComCharactersDiscovery;
import com.td.Dawa.game.comcharactersdiscovery.vo.ComCharactersDiscoveryClientVo;
import com.td.Dawa.game.comcharactersdiscovery.vo.ComCharactersDiscoveryVo;
import com.td.Dawa.game.comcharactersdiscovery.repository.ComCharactersDiscoveryRepository;
import com.td.Dawa.game.complayersattri.service.ComPlayersAttriService;
import com.td.Dawa.game.complayersattri.vo.ComPlayersAttriVo;
import com.td.Dawa.game.excelcharactercreate.pojo.ExcelCharacterCreate;
import com.td.Dawa.game.excelcharactercreate.service.ExcelCharacterCreateService;
import com.td.Dawa.game.excelcharacterlevel.service.ExcelCharacterLevelService;
import com.td.Dawa.game.excelcharacterlevel.vo.ExcelCharacterLevelVo;
import com.td.Dawa.game.exceldrop.pojo.ExcelDrop;
import com.td.Dawa.game.exceldrop.service.ExcelDropService;
import com.td.Dawa.game.exceldrop.vo.ExcelDropClientVo;
import com.td.Dawa.game.excelparameter.service.ExcelParameterService;
import com.td.Dawa.game.excelparameter.vo.ExcelParameterVo;
import com.td.Dawa.game.excelprop.pojo.ExcelProp;
import com.td.Dawa.game.excelprop.service.ExcelPropService;
import com.td.Dawa.game.excelprop.vo.ExcelPropClientVo;
import com.td.Dawa.game.excelresources.service.ExcelResourcesService;
import com.td.Dawa.game.excelresources.vo.ExcelResourcesClientVo;
import com.td.Dawa.game.excelscene.pojo.ExcelScene;
import com.td.Dawa.game.excelscene.service.ExcelSceneService;
import com.td.Dawa.game.excelworkpro.pojo.ExcelWorkPro;
import com.td.Dawa.game.excelworkpro.service.ExcelWorkProService;
import com.td.Dawa.game.excelworkpro.vo.ExcelWorkProVo;
import com.td.Dawa.util.CopyUtil;
import com.td.Dawa.util.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
@Slf4j
public class ComCharactersDiscoveryServiceImpl extends CommonServiceImpl<ComCharactersDiscoveryVo, ComCharactersDiscovery, Integer> implements ComCharactersDiscoveryService {

    @PersistenceContext
    private EntityManager em;
    @Autowired
    private ComCharactersDiscoveryRepository comCharactersDiscoveryRepository;

    @Autowired
    private ComCharactersService comCharactersService;

    @Autowired
    private ExcelDropService excelDropService;

    @Autowired
    private ExcelSceneService excelSceneService;

    @Autowired
    private ExcelCharacterLevelService excelCharacterLevelService;

    @Autowired
    private ComPlayersAttriService comPlayersAttriService;

    @Autowired
    private ExcelParameterService excelParameterService;

    @Autowired
    private ExcelResourcesService excelResourcesService;

    @Autowired
    private ExcelCharacterCreateService excelCharacterCreateService;

    @Autowired
    private ExcelWorkProService excelWorkProService;
    @Autowired
    private ExcelPropService excelPropService;

    /**
     * 开始工作
     *
     * @param userId
     * @param sceneId
     * @return
     */
    @Override
    public ComCharactersDiscoveryClientVo startDiscover(String userId, Integer sceneId) {

        ComCharactersDiscovery comCharacterDiscovery =
                comCharactersDiscoveryRepository.findByUserIdAndSceneId(userId, sceneId).orElse(null);
        if (comCharacterDiscovery == null || !StringUtils.hasText(comCharacterDiscovery.getRoleId())) {
            throw new AuthorizeException(ResultEnum.EXPLORATION_INFO_NULL);
        } else {
            if (comCharacterDiscovery.getIsWork().equals(GameEnum.WORK_ING.getValue())) {
                throw new AuthorizeException(ResultEnum.EXPLORATION_ING);
            }
            if (comCharacterDiscovery.getIsWork().equals(GameEnum.WORK_COMPLETE.getValue())) {
                throw new AuthorizeException(ResultEnum.EXPLORATION_COMPLETE);
            }

            //设置工作状态，设置工作开始时间
            comCharacterDiscovery.setIsWork(GameEnum.WORK_ING.getValue());
            comCharacterDiscovery.setWorkStart(DateUtil.date());

            ExcelParameterVo maxStrength = excelParameterService.getVo(1);
            ExcelParameterVo workConsumesStrength = excelParameterService.getVo(2); //消耗的体力单位
            if (maxStrength == null || workConsumesStrength == null) {
                throw new AuthorizeException(ResultEnum.SETTING_IS_NULL);
            }
            //todo 扣除一个体力值,判断是否超过设置的体力值
            ComPlayersAttriVo attriVo = comPlayersAttriService.findByUserId(userId);
            Integer _strength = attriVo.getStrength() + workConsumesStrength.getValue().intValue();
            if (maxStrength.getValue().intValue() < _strength) {
                //假如设置的值小于当前计算的体力，返回提示 当前体力不足，队伍无法工作
                throw new AuthorizeException(ResultEnum.PLAYER_ATTRIBUTE_STRENGTH_IS_NOT);
            }
            //消耗一个体力值(+1)
            attriVo.setStrength(_strength);
            comPlayersAttriService.save(attriVo);
        }
        ComCharactersDiscoveryVo comCharacterDiscoveryVo = CopyUtil.copy(comCharacterDiscovery, ComCharactersDiscoveryVo.class);
        //存储
        ComCharactersDiscoveryVo discoveryVo = super.save(comCharacterDiscoveryVo).getData();
        //先找出三个职业对象
        String[] roleId = discoveryVo.getRoleId().split("\\|");
        Integer[] _roleIds = Convert.toIntArray(roleId);
        List<ComCharacters> characters = comCharactersService.findByRoleIdIn(_roleIds);
        ComCharactersDiscoveryClientVo discoveryClientVo = CopyUtil.copy(discoveryVo, ComCharactersDiscoveryClientVo.class);
        //找出资源
        List<ComCharactersClientVo> comCharactersClientVos = characters.stream().map(e -> {
            ComCharactersClientVo comCharactersClientVo = new ComCharactersClientVo();
            comCharactersClientVo = CopyUtil.copy(e, ComCharactersClientVo.class);
            comCharactersClientVo = comCharactersService.addSubResourcesClientListToVO(comCharactersClientVo, e.getModelId(), e.getModelColor());
            //Integer[] _modelIdArray = Convert.toIntArray(e.getModelId().split("\\|"));
            ////查询position
            //List<ExcelCharacterCreate> _genList = excelCharacterCreateService.findByModelIn(_modelIdArray);
            //List<ExcelResourcesClientVo> resourcesList = excelResourcesService.findByArtIdIn(_modelIdArray).stream().map(_res -> {
            //    ExcelCharacterCreate excelCharacterCreate = _genList.stream().filter(_gen -> _gen.getModel().equals(_res.getArtId())).findFirst().get();
            //    _res.setPosition(excelCharacterCreate.getPosition());
            //    return _res;
            //}).collect(Collectors.toList());
            //comCharactersClientVo.setSubResourcesClientList(resourcesList);
            return comCharactersClientVo;
        }).collect(Collectors.toList());
        discoveryClientVo.setSubCharacters(comCharactersClientVos);//当前职业
        // 把当前时间设置到mill中
        discoveryClientVo.setWorkMill(discoveryVo.getWorkDay().longValue());
        //设置携带属性
        discoveryClientVo = setDiscoveryClientVoProAndTransNum(discoveryClientVo);

        //存储并且返回
        return discoveryClientVo;
    }

    /**
     * 添加角色,根据当前位置，设置工作类型，就是当前professional（1,2,3,4）
     *
     * @param charactersVo
     * @param sceneId
     * @return
     */
    @Override
    public ComCharactersDiscoveryClientVo addDiscoverRole(ComCharactersVo charactersVo, Integer sceneId) {

        //角色list
        List<ComCharactersClientVo> comCharactersClientVos = new ArrayList<>();
        ComCharactersDiscovery comCharacterDiscovery =
                comCharactersDiscoveryRepository.findByUserIdAndSceneId(charactersVo.getUserId(), sceneId).orElse(null);
        if (comCharacterDiscovery == null) {
            comCharacterDiscovery = new ComCharactersDiscovery();
            //新建一个队伍
            comCharacterDiscovery.setUserId(charactersVo.getUserId());
            comCharacterDiscovery.setRoleId(charactersVo.getId().toString());
            //comCharacterDiscovery.setName();
            comCharacterDiscovery.setIsWork(GameEnum.WORK_NOT_STARTED.getValue());//默认不工作
            comCharacterDiscovery.setWorkStart(DateUtil.date());
            ExcelParameterVo workMill = excelParameterService.getVo(6); //初始化工作时长
            comCharacterDiscovery.setWorkDay(workMill.getValue().intValue()); //工作时间，todo 暂时定60s
            comCharacterDiscovery.setWorkFlag(UUIDUtil.getUUID());
            comCharacterDiscovery.setDiscoverLevel(1); //默认探索第一层场景
            comCharacterDiscovery.setSceneId(sceneId); // 比如矿洞id对应的入口是201
            comCharacterDiscovery.setRewardExp(0); // 默认不奖励经验
            comCharacterDiscovery.setRewardCurrency(0); // 默认不奖励货币
            comCharacterDiscovery.setNote("工作队伍");

            comCharacterDiscovery.setCreateTime(DateUtil.date());
            comCharacterDiscovery.setUpdateTime(DateUtil.date());

            //没有角色，即把传入角色添加上
            comCharactersClientVos.add(CopyUtil.copy(charactersVo, ComCharactersClientVo.class));


        } else {
            String[] roleId = comCharacterDiscovery.getRoleId().split("\\|");
            Boolean isReplace = false; //是否是替换角色
            for (int i = 0; i < roleId.length; i++) {
                if (roleId[i].equals(charactersVo.getId().toString())) {
                    //不能添加相同的角色,直接返回一个查询的
                    //return CopyUtil.copy(comCharacterDiscovery, ComCharactersDiscoveryVo.class);
                    throw new AuthorizeException(ResultEnum.ROLE_ALREADY_ADD);
                } else {
                    ComCharactersVo _findCharacter = comCharactersService.getVo(Integer.parseInt(roleId[i]));
                    //如果当前职业相同，直接替换id
                    //log.info(_findCharacter.getProfessional() + "=" + charactersVo.getProfessional());
                    //列表角色和传入的角色做对比
                    if (_findCharacter.getProfessional().equals(charactersVo.getProfessional())) {
                        //如职业一样，替换列表中的角色
                        roleId[i] = charactersVo.getId().toString();
                        isReplace = true;
                        comCharactersClientVos.add(CopyUtil.copy(charactersVo, ComCharactersClientVo.class));
                    } else {
                        comCharactersClientVos.add(CopyUtil.copy(_findCharacter, ComCharactersClientVo.class));
                    }

                }
            }
            //如果不是替换，再旧的基础上添加一个角色
            if (!isReplace) {
                String _roleId = comCharacterDiscovery.getRoleId() + "|" + charactersVo.getId().toString();
                //如果最后没有替换到列表，说明没有角色，即把传入角色添加上
                comCharactersClientVos.add(CopyUtil.copy(charactersVo, ComCharactersClientVo.class));
                comCharacterDiscovery.setRoleId(_roleId);
            } else {
                comCharacterDiscovery.setRoleId(String.join("|", roleId));
            }
            comCharacterDiscovery.setUpdateTime(DateUtil.date());
        }
        //保存一次用户修改的当前职业工作标签profession，工作位置workPos,工作结算时候，重置一次为零
        comCharactersService.save(charactersVo);

        ComCharactersDiscoveryVo comCharacterDiscoveryVo = CopyUtil.copy(comCharacterDiscovery, ComCharactersDiscoveryVo.class);
        super.save(comCharacterDiscoveryVo);
        ComCharactersDiscoveryClientVo comCharacterDiscoveryClientVo = CopyUtil.copy(comCharacterDiscoveryVo, ComCharactersDiscoveryClientVo.class);
        comCharacterDiscoveryClientVo.setSubCharacters(comCharactersClientVos);
        //设置携带属性
        comCharacterDiscoveryClientVo = setDiscoveryClientVoProAndTransNum(comCharacterDiscoveryClientVo);
        return comCharacterDiscoveryClientVo;
    }


    @Override
    public PageInfo<ComCharactersDiscoveryClientVo> findDiscoverClientVo(ComCharactersDiscoveryVo characterDiscoveryVo) {
        PageInfo<ComCharactersDiscoveryVo> comCharactersDiscoveryVo = super.page(characterDiscoveryVo).getData();
        //获取到探索队伍的数据
        List<ComCharactersDiscoveryVo> _listVo = comCharactersDiscoveryVo.getRows();
        List<ComCharactersDiscoveryClientVo> _discoveryClientVos = new ArrayList<>();
        for (ComCharactersDiscoveryVo discoveryVo : _listVo) {
            String[] roleId = discoveryVo.getRoleId().split("\\|");
            //角色list
            List<ComCharactersClientVo> comCharactersClientVos = new ArrayList<>();
            for (int i = 0; i < roleId.length; i++) {
                ComCharactersVo comCharactersVo = comCharactersService.getVo(Integer.parseInt(roleId[i]));
                ComCharactersClientVo comCharactersClientVo = CopyUtil.copy(comCharactersVo, ComCharactersClientVo.class);
                //List<ExcelCharacterCreate> subExcelCharacterList = listMap.get(excelCharacterAttr.getRoleType());
                //character.setSubCreateClientList(CopyUtil.copyList(subExcelCharacterList,ExcelCharacterCreateClientVo.class));
                comCharactersClientVos.add(comCharactersClientVo);
            }
            //开始工作时间 + 工作天数
            Date endDate = DateUtil.offsetMillisecond(discoveryVo.getWorkStart(), discoveryVo.getWorkDay());
            //
            Long dif = 0L;
            if (discoveryVo.getIsWork().equals(GameEnum.WORK_ING.getValue())) {
                //如果已经开始工作，计算当前时间与结束时间的毫秒
                dif = DateUtil.between(DateUtil.date(), endDate, DateUnit.MS, false);
                if (dif <= 0L) {
                    //工作完成
                    discoveryVo.setIsWork(GameEnum.WORK_COMPLETE.getValue());
                    super.save(discoveryVo);
                    dif = 0L;
                }
            } else {
                //还没开始工作，返回开始和结束直接的毫秒
                dif = DateUtil.between(discoveryVo.getWorkStart(), endDate, DateUnit.MS, false);
                if (dif <= 0L) {
                    dif = 0L;
                }
            }

            ComCharactersDiscoveryClientVo comCharacterDiscoveryClientVo = CopyUtil.copy(discoveryVo, ComCharactersDiscoveryClientVo.class);
            //小于等于零即完成
            comCharacterDiscoveryClientVo.setWorkMill(dif);
            comCharacterDiscoveryClientVo.setSubCharacters(comCharactersClientVos);
            //设置携带属性
            comCharacterDiscoveryClientVo = setDiscoveryClientVoProAndTransNum(comCharacterDiscoveryClientVo);
            _discoveryClientVos.add(comCharacterDiscoveryClientVo);
        }

        PageInfo<ComCharactersDiscoveryClientVo> backPageInfo = new PageInfo<>();
        backPageInfo.setRows(_discoveryClientVos);
        backPageInfo.setPage(comCharactersDiscoveryVo.getPage());
        backPageInfo.setPageSize(comCharactersDiscoveryVo.getPageSize());
        backPageInfo.setTotal(comCharactersDiscoveryVo.getTotal());
        backPageInfo.setRecords(comCharactersDiscoveryVo.getRecords());
        backPageInfo.setSidx(comCharactersDiscoveryVo.getSidx());
        backPageInfo.setSord(comCharactersDiscoveryVo.getSord());
        return backPageInfo;
    }

    /**
     * 挖矿工作状态
     * 1.工作时间未完结时候，刷新按照最后一次updateTime来判定是否重新计算产出，假如挖矿和勘探分别有不同的时间
     * 2.工作未完结时间，记录当前产出的物品和产出m
     * 3.工作完结，删除工作队列，相关产出转移背包，计算经验等。（删除的队列进入回收列表）
     * 4.可中途结束工作
     *
     * @param discoveryVo
     * @return
     */
    @Override
    public ComCharactersDiscoveryClientVo explorationState(ComCharactersDiscoveryVo discoveryVo, Boolean isStop) {
        if (discoveryVo.getIsWork().equals(GameEnum.WORK_NOT_STARTED.getValue())) {
            throw new AuthorizeException(ResultEnum.EXPLORATION_NOT_START);
        }
        //todo 经验如何设置
        List<ExcelParameterVo> parameterVos = excelParameterService.list(new ExcelParameterVo()).getData();
        ExcelParameterVo parameter = parameterVos.get(6); //初始化工作经验
        Integer outExp = parameter.getValue().intValue();
        //当前关卡奖励的经验
        discoveryVo.setRewardExp(outExp);
        //todo 获取当前人物等级经验表，待优化
        List<ExcelCharacterLevelVo> excelCharacterLevelVo = excelCharacterLevelService.list(new ExcelCharacterLevelVo()).getData();
        //已产生的奖励物品
        String[] _hasDropIds = StringUtils.hasText(discoveryVo.getRewardItem()) ? discoveryVo.getRewardItem().split("\\|") : new String[0];
        //奖励物品的计数
        String[] _hasDropCounts = StringUtils.hasText(discoveryVo.getRewardCount()) ? discoveryVo.getRewardCount().split("\\|") : new String[0];
        //总共参数的奖励物品
        String[] _allDropIds = StringUtils.hasText(discoveryVo.getRewardCount()) ? discoveryVo.getAllItem().split("\\|") : new String[0];
        //记录当前的产出奖励
        List<ExcelPropClientVo> outExcelProps = new ArrayList<>();

        //开始工作时间 + 工作天数
        Date endDate = DateUtil.offsetMillisecond(discoveryVo.getWorkStart(), discoveryVo.getWorkDay());
        //用更新数据时间与最终偏移时间点来计算 当前的秒数，为零说明工作完成
        Long difSecond = DateUtil.between(discoveryVo.getUpdateTime(), endDate, DateUnit.SECOND, false);
        if (difSecond <= 0L) {
            difSecond = 0L;//这里difSecond是用户更新数据计算所剩余的时间
        }
        log.info("剩余计算的时长difSecond：" + difSecond);
        //当前时间与结束时间的毫秒
        Long dif = DateUtil.between(DateUtil.date(), endDate, DateUnit.MS, false);

        //判断是否结束工作 小于等于零即完成
        if (dif <= 0L) {
            discoveryVo.setIsWork(GameEnum.WORK_COMPLETE.getValue());
            dif = 0L;
        } else if (isStop) {
            //工作时长未完结，不可停止
            throw new AuthorizeException(ResultEnum.EXPLORATION_NOT_STOP);
        }

        //todo 根据场景id获取当前场景配置 后面处理缓存，提高速度
        //获取场景全部列表
        //List<ExcelScene> excelSceneList = excelSceneService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_SCENE.getMessage());
        //主场景id
        ExcelScene excelScene = excelSceneService.findBySceneId(discoveryVo.getSceneId());
        //if (!StringUtils.hasText(excelScene.getSceneEvent())) {
        //    throw new RuntimeException("scene event 奖励未配置");
        //}
        //获取当前的一个基础数量
        Integer outTransUpperLimit = excelScene.getAmount();
        //当前场景层级对应的物品
        //String[] _dropIds = excelScene.getSceneEvent().split("\\|");
        //List<ExcelDrop> currentSceneExcelDrops = excelDropService.getListByDropIds(Convert.toIntArray(_dropIds));

        //获取概率表数据（缓存取）
        List<ExcelWorkPro> workProList = excelWorkProService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_WORK_PRO.getMessage());
        //获取当前道具表
        List<ExcelProp> propList = excelPropService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_PROP.getMessage());

        //已经挖出的全部道具
        List<String> _allDropIdList = Arrays.asList(_allDropIds);
        List<ExcelProp> allExcelProps = propList.stream().filter(e -> _allDropIdList.contains(e.getPropId().toString())).collect(Collectors.toList());
        // 这里返回的是挖取出来的物品
        List<ExcelPropClientVo> allPropClientVoList = allExcelProps.stream().map(e -> {
            ExcelPropClientVo _vo = CopyUtil.copy(e, ExcelPropClientVo.class);
            _vo.setItemNum(0);
            return _vo;
        }).collect(Collectors.toList());
        //已经得到的奖励
        for (int i = 0; i < _hasDropIds.length; i++) {
            //if (ArrayUtil.contains(_allDropIds, _hasDropIds[i])) {
            //    int _index = ArrayUtil.indexOf(_allDropIds, _hasDropIds[i]);
            //    ExcelDropClientVo _dropClientVo = allDropClientVos.get(_index);
            //    int _dropCount = Integer.parseInt(ArrayUtil.get(_hasDropCounts, i));//根据id获取记录的count
            //    _dropClientVo.setCount(_dropCount);
            //    outExcelProps.add(_dropClientVo);
            //}
            if (_allDropIdList.contains(_hasDropIds[i])) {
                int _index = _allDropIdList.indexOf(_hasDropIds[i]);
                ExcelPropClientVo _dropClientVo = allPropClientVoList.get(_index);
                int _dropCount = Integer.parseInt(ArrayUtil.get(_hasDropCounts, i));//根据id获取记录的count
                _dropClientVo.setItemNum(_dropCount);
                outExcelProps.add(_dropClientVo);
            }

        }

        //当前探索队伍
        String[] roleId = discoveryVo.getRoleId().split("\\|");
        Integer[] _roleIds = Convert.toIntArray(roleId);

        //角色list
        List<ComCharactersClientVo> comCharactersClientVos = new ArrayList<>();


        //先找出三个职业对象
        ComCharactersVo powerChar = null, intelliChar = null, skillChar = null;
        ExcelWorkPro _excelWorkPro = null;
        String[] _levelItemList = new String[0];
        List<ExcelProp> currentExcelProps;
        List<String> _levelPropIds;
        List<ComCharacters> characters = comCharactersService.findByRoleIdIn(_roleIds);
        //设置一个默认的基础数量
        for (int i = 0; i < characters.size(); i++) {
            ComCharactersVo comCharactersVo = CopyUtil.copy(characters.get(i), ComCharactersVo.class); //comCharactersService.getVo(Integer.parseInt(roleId[i]));
            //根据当前角色的职业计算
            Integer _professional = comCharactersVo.getProfessional();
            if (_professional.equals(GameEnum.PRO_WORK_TRANSPORT.getValue())) {
                //_professional.equals(GameEnum.PRO_SKIlLS.getValue()
                //运输工
                skillChar = comCharactersVo;
                //计算当前运输格数，即获取到物品的上限
                //场景的最低运输数量
                Integer _selfLimit = getLimitSkillsAndList(comCharactersVo.getSkills(), workProList);
                if (_selfLimit > outTransUpperLimit) {
                    outTransUpperLimit = _selfLimit;
                }
            } else if (_professional.equals(GameEnum.PRO_WORK_MINING.getValue()) ||
                    _professional.equals(GameEnum.PRO_WORK_LUMBERING.getValue())) {
                //_professional.equals(GameEnum.PRO_POWER.getValue())
                //矿工
                powerChar = comCharactersVo;
            } else if (_professional.equals(GameEnum.PRO_WORK_PROSPECT.getValue())) {
                //_professional.equals(GameEnum.PRO_INTELLIGENCE.getValue())
                //勘测地形
                intelliChar = comCharactersVo;
            }

        }
        if (powerChar != null) {
            //  每3秒执行一次挖矿动作。根据属性数值概率，获得收益
            //  矿工有休息动作，休息时间3秒
            // 勘探：
            Integer _power = powerChar.getPower();
            //获取当前工作的效率表
            _excelWorkPro = getRatioByPowerAndSceneIdAndList(_power, discoveryVo.getSceneId(), workProList);
            //道具和道具对应的概率
            _levelItemList = _excelWorkPro.getLevelItem().split(",");
            String _levelProp = ArrayUtil.get(_levelItemList, discoveryVo.getDiscoverLevel() - 1);//获取当前层级的道具
            String[] _mainAndProp = _levelProp.split("\\|");
            _levelPropIds = Arrays.asList(ArrayUtil.remove(_mainAndProp, 0)); //对应的id list
            String _levelSceneId = _mainAndProp[0];//第一个是场景id，移除
            List<String> final_levelPropIds = _levelPropIds;
            currentExcelProps = propList.stream().filter(e -> final_levelPropIds.contains(e.getPropId().toString())).collect(Collectors.toList());//过滤后的当前场景可获得的道具
            String[] _levelProList = _excelWorkPro.getLevelPro().split(",");
            String _levelPropPro = ArrayUtil.get(_levelProList, discoveryVo.getDiscoverLevel() - 1);//获取当前层级的道具对应的概率
            String[] _mainAndPropPro = _levelPropPro.split("\\|");
            List<String> _levelPropProList = Arrays.asList(ArrayUtil.remove(_mainAndPropPro, 0)); //对应的概率id list
            String _level = _mainAndPropPro[0];//第一个是场景level，移除

            int _miningInterval = parameterVos.get(3).getValue().intValue();//挖矿时间间隔
            log.info("挖矿间隔时间：" + _miningInterval);
            int _count = (int) Math.floor(difSecond / _miningInterval); // 一共执行的工作次数和休息
            log.info("执行的工作次数：" + _count);
            //按次数执行奖励
            //对应物品数量少于或等于运输数量
            for (int j = 0; j < _count; j++) {
                //采集x4+休息x1
                if (j % 5 != 0) {
                    //工作，并且奖励物品
                    //1.先判定Probability， 2.再判定Currency是不是挖到货币或道具  3.挖到道具 再计算道具概率掉落
                    Double _getProbability = _excelWorkPro.getProbability() / 100;
                    log.info("_getProbability:" + _getProbability);
                    if (NumberUtil.compare(new Random().nextDouble(), _getProbability) <= 0) {
                        Double _currencyPro = Double.parseDouble(_excelWorkPro.getCurrency() + "") / 100;
                        log.info("当前计算货币概率: " + _currencyPro);
                        if (NumberUtil.compare(new Random().nextDouble(), _currencyPro) > 0) {//物品概率
                            //随机获取一个物品，再判断物品概率是否掉落
                            int index = (int) (Math.random() * currentExcelProps.size());
                            ExcelProp _clientVo = currentExcelProps.get(index); //随机获得道具
                            Double _clientPro = Double.parseDouble(_levelPropProList.get(index)) / 100;//随机获得道具对应的概率
                            if (NumberUtil.compare(new Random().nextDouble(), _clientPro) <= 0) {
                                //todo 如果挖了多少个，添加上去
                                if (ArrayUtil.contains(_hasDropIds, _clientVo.getPropId().toString())) {
                                    //已经存在的下标
                                    int _index = ArrayUtil.indexOf(_hasDropIds, _clientVo.getPropId().toString());
                                    int _dropCount = Integer.parseInt(ArrayUtil.get(_hasDropCounts, _index));//根据id获取记录的count
                                    _dropCount = _dropCount + 1;
                                    _hasDropCounts = ArrayUtil.setOrAppend(_hasDropCounts, _index, _dropCount + "");//添加1个数量
                                    //重新设置count+1
                                    ExcelPropClientVo _propClientVo = outExcelProps.get(_index);
                                    _propClientVo.setItemNum(_dropCount);

                                } else if (outExcelProps.size() < outTransUpperLimit) {
                                    _hasDropIds = ArrayUtil.append(_hasDropIds, _clientVo.getPropId().toString());
                                    _hasDropCounts = ArrayUtil.append(_hasDropCounts, "1");//新添加
                                    outExcelProps.add(CopyUtil.copy(_clientVo, ExcelPropClientVo.class));
                                }
                            }

                            if (!ArrayUtil.contains(_allDropIds, _clientVo.getPropId().toString())) {
                                //如果没添加过，添加一次物品
                                _allDropIds = ArrayUtil.append(_allDropIds, _clientVo.getPropId().toString());
                                ExcelPropClientVo _propClientVo = CopyUtil.copy(_clientVo, ExcelPropClientVo.class);
                                _propClientVo.setItemNum(0);
                                allPropClientVoList.add(_propClientVo);
                            }
                        } else {
                            //剩余获得货币
                            log.info("增加货币");
                            //todo 货币数据未给出，暂定100
                            ExcelParameterVo _currency = excelParameterService.getVo(8);
                            int _num = (int) Math.round(_currency.getValue());
                            discoveryVo.setRewardCurrency(discoveryVo.getRewardCurrency() == null ? _num : discoveryVo.getRewardCurrency() + _num);
                        }

                    }
                }
            }

            //完结后三个分别增加经验
            //收获经验 todo 处理人物升级等
            ComCharactersClientVo comCharactersClientVo = upgradeComCharactersVo(powerChar, excelCharacterLevelVo, outExp);
            comCharactersClientVo = comCharactersService.addSubResourcesClientListToVO(comCharactersClientVo, powerChar.getModelId(), powerChar.getModelColor());
            comCharactersClientVos.add(comCharactersClientVo);
        }
        if (intelliChar != null) {
            //勘测地形，用于进入下层场景的职业
            //每15秒执行一次勘探。根据属性数值概率，前往下层洞穴
            //洞穴影响矿石类型产出,最后一层不用再计算概率
            if (!discoveryVo.getDiscoverLevel().equals(GameEnum.LIMIT_LEVEL.getValue())) {
                Integer _intelligence = intelliChar.getIntelligence();
                int _explorationInterval = parameterVos.get(4).getValue().intValue();//挖矿时间间隔
                log.info("勘探间隔时间：" + _explorationInterval);
                int _count = (int) Math.floor(difSecond / _explorationInterval); // 一共执行勘探的次数
                //按次数执行奖励
                for (int j = 0; j < _count; j++) {
                    //计算是否进入下一层的概率
                    double _nextRatio = gotoNextSceneRatioAndList(discoveryVo.getDiscoverLevel(), _intelligence, workProList);
                    if (NumberUtil.compare(new Random().nextDouble(), _nextRatio) <= 0) {
                        //todo 切换关卡的奖励物品
                        Integer _currentLevel = discoveryVo.getDiscoverLevel() + 1;
                        discoveryVo.setDiscoverLevel(_currentLevel);
                        super.save(discoveryVo); // 更新数据
                        //切换场景id
                        if (_excelWorkPro != null) { //道具和道具对应的概率
                            String _levelProp = ArrayUtil.get(_levelItemList, _currentLevel - 1);//获取当前层级的道具
                            String[] _mainAndProp = _levelProp.split("\\|");
                            _levelPropIds = Arrays.asList(ArrayUtil.remove(_mainAndProp, 0)); //对应的id list
                            String _levelSceneId = _mainAndProp[0];//第一个是场景id，移除
                            List<String> final_levelPropIds = _levelPropIds;
                            currentExcelProps = propList.stream().filter(e -> final_levelPropIds.contains(e.getPropId().toString())).collect(Collectors.toList());//过滤后的当前场景可获得的道具
                        }

                    }
                }
            }
            //完结后三个分别增加经验
            //收获经验 todo 处理人物升级等
            ComCharactersClientVo comCharactersClientVo = upgradeComCharactersVo(intelliChar, excelCharacterLevelVo, outExp);
            comCharactersClientVo = comCharactersService.addSubResourcesClientListToVO(comCharactersClientVo, intelliChar.getModelId(), intelliChar.getModelColor());
            comCharactersClientVos.add(comCharactersClientVo);
        }
        if (skillChar != null) {
            //完结后三个分别增加经验
            //收获经验 todo 处理人物升级等
            ComCharactersClientVo comCharactersClientVo = upgradeComCharactersVo(skillChar, excelCharacterLevelVo, outExp);
            comCharactersClientVo = comCharactersService.addSubResourcesClientListToVO(comCharactersClientVo, skillChar.getModelId(), skillChar.getModelColor());
            comCharactersClientVos.add(comCharactersClientVo);
        }
        ComCharactersDiscoveryClientVo discoveryClientVo = CopyUtil.copy(discoveryVo, ComCharactersDiscoveryClientVo.class);

        discoveryClientVo.setSubCharacters(comCharactersClientVos);//当前职业
        discoveryClientVo.setWorkMill(dif);//倒计时
        //List<ExcelDropClientVo> _getDrops = outExcelDrops.subList(0, outTransUpperLimit);
        //记录一个物品获得情况
        //List<String> _getDropIds = _getDrops.stream().map(e -> e.getId().toString()).collect(Collectors.toList());
        String _rewardItem = String.join("|", _hasDropIds);
        String _rewardCounts = String.join("|", _hasDropCounts);
        String _allItems = String.join("|", _allDropIds);
        discoveryVo.setRewardItem(_rewardItem);
        discoveryVo.setRewardCount(_rewardCounts);
        discoveryVo.setAllItem(_allItems);

        //保存挖矿数据
        //设置一次updateTime
        discoveryVo.setUpdateTime(DateUtil.date());
        //todo 工作完成后，isStop
        if (discoveryVo.getIsWork().equals(GameEnum.WORK_COMPLETE.getValue()) && isStop) {
            //重置人物角色职业工作状态
            if(powerChar!=null){
                powerChar.setProfessional(GameEnum.PRO_WORK_NORMAL.getValue());
                powerChar.setWorkPos(0);
                comCharactersService.save(powerChar);
            }
            if(intelliChar!=null){
                intelliChar.setProfessional(GameEnum.PRO_WORK_NORMAL.getValue());
                intelliChar.setWorkPos(0);
                comCharactersService.save(intelliChar);
            }
            if(skillChar!=null){
                skillChar.setProfessional(GameEnum.PRO_WORK_NORMAL.getValue());
                skillChar.setWorkPos(0);
                comCharactersService.save(skillChar);
            }
            super.delete(discoveryVo.getId());
        } else {
            //todo 后续优化，不用每次都存储
            super.save(discoveryVo);
        }
        //输出限制
        discoveryClientVo.setSubGetDrops(outExcelProps);//当前产出物品
        //全部的奖励物品
        discoveryClientVo.setSubAllDrops(allPropClientVoList);

        //设置携带属性
        discoveryClientVo = setDiscoveryClientVoProAndTransNum(discoveryClientVo);
        return discoveryClientVo;
    }


    //private ComCharactersClientVo addSubResourcesClientList(ComCharactersClientVo comCharactersClientVo ,String _modelIdStr){
    //    Integer[] _modelIdArray = Convert.toIntArray(_modelIdStr.split("\\|"));
    //    //查询position
    //    List<ExcelCharacterCreate> _genList = excelCharacterCreateService.findByModelIn(_modelIdArray);
    //    List<ExcelResourcesClientVo> resourcesList = excelResourcesService.findByArtIdIn(_modelIdArray).stream().map(_res -> {
    //        ExcelCharacterCreate excelCharacterCreate = _genList.stream().filter(_gen -> _gen.getModel().equals(_res.getArtId())).findFirst().get();
    //        _res.setPosition(excelCharacterCreate.getPosition());
    //        return _res;
    //    }).collect(Collectors.toList());
    //    comCharactersClientVo.setSubResourcesClientList(resourcesList);
    //    return comCharactersClientVo;
    //}

    /**
     * 存储
     *
     * @param comCharactersVo
     */
    private ComCharactersClientVo upgradeComCharactersVo(ComCharactersVo comCharactersVo, List<ExcelCharacterLevelVo> excelCharacterLevelVo, Integer outExp) {
        if (comCharactersVo.getExp() == null) {
            throw new RuntimeException("upgrade characters exp is null！");
        }
        if (comCharactersVo.getLevel() == null) {
            throw new RuntimeException("upgrade characters level is null！");
        }
        Integer _exp = comCharactersVo.getExp() + outExp;
        Integer _level = comCharactersVo.getLevel(); // 这里等级至少是1级

        Integer final_level = _level;
        ExcelCharacterLevelVo characterLevelVo = excelCharacterLevelVo.stream().filter(e -> e.getId().equals(final_level)).findFirst().get();


        while (_exp > characterLevelVo.getExp()) {
            _exp -= characterLevelVo.getExp();
            _level += 1;//提升一级
            Integer final_level2 = _level;
            characterLevelVo = excelCharacterLevelVo.stream().filter(e -> e.getId().equals(final_level2)).findFirst().get();
        }
        //最后的等级和经验
        comCharactersVo.setLevel(_level);
        comCharactersVo.setExp(_exp);
        //存储一次
        comCharactersService.save(comCharactersVo);
        ComCharactersClientVo comCharactersClientVo = CopyUtil.copy(comCharactersVo, ComCharactersClientVo.class);
        //返回当前需要升级的经验
        comCharactersClientVo.setLevelUpExp(characterLevelVo.getExp());
        return comCharactersClientVo;
    }


    /**
     * 设置discoveryClientVo带的两个概率和一个运输数量
     *
     * @param clientVo
     * @return
     */
    private ComCharactersDiscoveryClientVo setDiscoveryClientVoProAndTransNum(ComCharactersDiscoveryClientVo clientVo) {
        //获取概率表数据（缓存取）
        List<ExcelWorkPro> workProList = excelWorkProService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_WORK_PRO.getMessage());
        //主场景id
        ExcelScene excelScene = excelSceneService.findBySceneId(clientVo.getSceneId());
        if (excelScene.getAmount() == null) {
            throw new RuntimeException("excelScene amount is null");
        }
        Integer outTransUpperLimit = excelScene.getAmount();
        clientVo.setTransQuantity(outTransUpperLimit);

        List<ComCharactersClientVo> voList = clientVo.getSubCharacters();
        for (int i = 0; i < clientVo.getSubCharacters().size(); i++) {
            ComCharactersClientVo charactersClientVo = voList.get(i);
            Integer _professional = charactersClientVo.getProfessional();
            if (_professional.equals(GameEnum.PRO_WORK_TRANSPORT.getValue())) {
                //_professional.equals(GameEnum.PRO_SKIlLS.getValue())
                //运输工
                //计算当前运输格数，即获取到物品的上限
                //场景的最低运输数量
                Integer _selfLimit = getLimitSkillsAndList(charactersClientVo.getSkills(), workProList);
                if (_selfLimit > outTransUpperLimit) {
                    clientVo.setTransQuantity(_selfLimit);
                }
            } else if (_professional.equals(GameEnum.PRO_WORK_MINING.getValue()) ||
                    _professional.equals(GameEnum.PRO_WORK_LUMBERING.getValue())) {
                //_professional.equals(GameEnum.PRO_POWER.getValue())
                //矿工
                ExcelWorkPro excelWorkPro = getRatioByPowerAndSceneIdAndList(charactersClientVo.getPower(), clientVo.getSceneId(), workProList);
                //todo 这个概率可能还要计算
                clientVo.setPowerPro(excelWorkPro.getProbability());
            } else if (_professional.equals(GameEnum.PRO_WORK_PROSPECT.getValue())) {
                //_professional.equals(GameEnum.PRO_INTELLIGENCE.getValue())
                //勘测地形
                clientVo.setIntelliPro(gotoNextSceneRatioAndList(clientVo.getDiscoverLevel(), charactersClientVo.getIntelligence(), workProList));
            }
        }
        return clientVo;
    }

    /**
     * 直接设置获得道具的概率
     *
     * @param value       当前力量值
     * @param mainSceneId 主场景id
     * @param workProList
     * @return
     */
    private ExcelWorkPro getRatioByPowerAndSceneIdAndList(Integer value, Integer mainSceneId, List<ExcelWorkPro> workProList) {
        //取最接近value的一个最小值
        if (mainSceneId.equals(GameEnum.MINE_00.getValue())) {
            //如果是挖矿场景id
            ExcelWorkPro excelWorkPro = workProList.stream().filter(e -> e.getProfessionalType().equals(1) && e.getAttribute() <= value).max(Comparator.comparing(u -> u.getAttribute())).get();
            return excelWorkPro;
        } else if (mainSceneId.equals(GameEnum.LUMBERING_00.getValue())) {
            //如果是伐木场景id
            List<ExcelWorkPro> workPros = workProList.stream().filter(e -> e.getProfessionalType().equals(4) && e.getAttribute() >= value).collect(Collectors.toList());

            log.info(workPros.toString());
            ExcelWorkPro excelWorkPro = workProList.stream().filter(e -> e.getProfessionalType().equals(4) && e.getAttribute() <= value).max(Comparator.comparing(u -> u.getAttribute())).get();
            return excelWorkPro;
        } else {
            throw new RuntimeException("No mainSceneId value");
        }
    }

    private double getRatioByPower(Integer value) {
        double _ratio = 0d;
        if (value >= GameEnum.ATTRIBUTE_01.getValue() && value < GameEnum.ATTRIBUTE_02.getValue()) {
            //60~100
            _ratio = 0.004;
        } else if (value < GameEnum.ATTRIBUTE_03.getValue()) {
            //100~140
            _ratio = 0.006;
        } else if (value < GameEnum.ATTRIBUTE_04.getValue()) {
            //140~180
            _ratio = 0.01;
        } else if (value < GameEnum.ATTRIBUTE_05.getValue()) {
            //180~220
            _ratio = 0.015;
        } else if (value < GameEnum.ATTRIBUTE_06.getValue()) {
            //220~260
            _ratio = 0.02;
        } else {
            //>=260
            _ratio = 0.025;
        }
        return _ratio;
    }

    /**
     * 根据当前场景的层级和属性值获取一个进入下个场景的概率
     *
     * @param sceneLevel
     * @param value
     * @return
     */
    private double gotoNextSceneRatioAndList(Integer sceneLevel, Integer value, List<ExcelWorkPro> workProList) {
        //取最接近value的一个最小值
        ExcelWorkPro excelWorkPro = workProList.stream().filter(e -> e.getProfessionalType().equals(2) && e.getAttribute() <= value).max(Comparator.comparing(u -> u.getAttribute())).get();
        String[] exploration = excelWorkPro.getExploration().split("\\|");//层级参数
        String[] enterPro = excelWorkPro.getEnterPro().split("\\|");//层级参数对应的概率
        Double _ratio = 0d;
        String netLevel = String.valueOf(sceneLevel + 1);
        if (ArrayUtil.contains(exploration, netLevel)) {
            int index = ArrayUtil.indexOf(exploration, netLevel);
            log.info(Integer.parseInt(ArrayUtil.get(enterPro, index)) + "");
            _ratio = Double.parseDouble(ArrayUtil.get(enterPro, index)) / 100;
        }
        return _ratio;
    }

    private double gotoNextSceneRatio(Integer sceneLevel, Integer value) {
        double _ratio = 0d;
        if (value >= GameEnum.ATTRIBUTE_01.getValue() && value < GameEnum.ATTRIBUTE_02.getValue()) {
            //60~100
            if (sceneLevel.equals(1)) {
                _ratio = 0.04;  // 1=>2
            }
        } else if (value < GameEnum.ATTRIBUTE_03.getValue()) {
            //100~140
            _ratio = 0.006;
            if (sceneLevel.equals(1)) {
                _ratio = 0.11;  // 1=>2
            } else if (sceneLevel.equals(2)) {
                _ratio = 0.1;  // 2=>3
            }
        } else if (value < GameEnum.ATTRIBUTE_04.getValue()) {
            //140~180
            if (sceneLevel.equals(1)) {
                _ratio = 0.23;  // 1=>2
            } else if (sceneLevel.equals(2)) {
                _ratio = 0.03;  // 2=>3
            } else if (sceneLevel.equals(3)) {
                _ratio = 0.01;  // 3=>4
            }
        } else if (value < GameEnum.ATTRIBUTE_05.getValue()) {
            //180~220
            if (sceneLevel.equals(1)) {
                _ratio = 0.34;  // 1=>2
            } else if (sceneLevel.equals(2)) {
                _ratio = 0.07;  // 2=>3
            } else if (sceneLevel.equals(3)) {
                _ratio = 0.03;  // 3=>4
            }
        } else if (value < GameEnum.ATTRIBUTE_06.getValue()) {
            //220~260
            if (sceneLevel.equals(1)) {
                _ratio = 0.51;  // 1=>2
            } else if (sceneLevel.equals(2)) {
                _ratio = 0.11;  // 2=>3
            } else if (sceneLevel.equals(3)) {
                _ratio = 0.07;  // 3=>4
            }
        } else {
            //>=260
            if (sceneLevel.equals(1)) {
                _ratio = 0.97;  // 1=>2
            } else if (sceneLevel.equals(2)) {
                _ratio = 0.19;  // 2=>3
            } else if (sceneLevel.equals(3)) {
                _ratio = 0.13;  // 3=>4
            }
        }
        return _ratio;
    }

    /**
     * 获得当前的运输数量值
     *
     * @param value
     * @param workProList
     * @return
     */
    private int getLimitSkillsAndList(Integer value, List<ExcelWorkPro> workProList) {
        //取最接近value的一个最小值
        ExcelWorkPro excelWorkPro = workProList.stream().filter(e -> e.getProfessionalType().equals(3) && e.getAttribute() <= value).max(Comparator.comparing(u -> u.getAttribute())).get();
        return excelWorkPro.getTransport();
    }

    private int getLimitSkills(Integer value) {
        int _limit = 0;
        if (value >= GameEnum.ATTRIBUTE_01.getValue() && value < GameEnum.ATTRIBUTE_02.getValue()) {
            //60~100
            _limit = 5;
        } else if (value < GameEnum.ATTRIBUTE_03.getValue()) {
            //100~140
            _limit = 10;
        } else if (value < GameEnum.ATTRIBUTE_04.getValue()) {
            //140~180
            _limit = 15;
        } else if (value < GameEnum.ATTRIBUTE_05.getValue()) {
            //180~220
            _limit = 20;
        } else if (value < GameEnum.ATTRIBUTE_06.getValue()) {
            //220~260
            _limit = 25;
        } else {
            //>=260
            _limit = 30;
        }
        return _limit;
    }


    private int getSceneIdByLevel(Integer value, Integer sceneType) {
        int _levelId = 0;
        if (sceneType >= 101 || sceneType <= 105) {
            if (value.equals(1)) {
                _levelId = GameEnum.LUMBERING_00.getValue();
            } else if (value.equals(2)) {
                _levelId = GameEnum.LUMBERING_01.getValue();
            } else if (value.equals(3)) {
                _levelId = GameEnum.LUMBERING_02.getValue();
            } else if (value.equals(4)) {
                _levelId = GameEnum.LUMBERING_03.getValue();
            } else if (value.equals(5)) {
                _levelId = GameEnum.LUMBERING_04.getValue();
            }
            //伐木
        } else if (sceneType >= 201 || sceneType <= 205) {
            if (value.equals(1)) {
                _levelId = GameEnum.MINE_00.getValue();
            } else if (value.equals(2)) {
                _levelId = GameEnum.MINE_01.getValue();
            } else if (value.equals(3)) {
                _levelId = GameEnum.MINE_02.getValue();
            } else if (value.equals(4)) {
                _levelId = GameEnum.MINE_03.getValue();
            } else if (value.equals(5)) {
                _levelId = GameEnum.MINE_04.getValue();
            }
        }

        return _levelId;
    }
}
