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

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import com.td.Dawa.annotation.In;
import com.td.Dawa.common.service.*;
import com.td.Dawa.config.enums.GameEnum;
import com.td.Dawa.game.comcharacters.pojo.ComCharacters;
import com.td.Dawa.game.comcharacters.vo.*;
import com.td.Dawa.game.comcharacters.repository.ComCharactersRepository;
import com.td.Dawa.game.excelcharacterattri.pojo.ExcelCharacterAttri;
import com.td.Dawa.game.excelcharacterattri.repository.ExcelCharacterAttriRepository;
import com.td.Dawa.game.excelcharacterattri.service.ExcelCharacterAttriService;
import com.td.Dawa.game.excelcharacterattri.vo.ExcelCharacterAttriVo;
import com.td.Dawa.game.excelcharactercolor.pojo.ExcelCharacterColor;
import com.td.Dawa.game.excelcharactercolor.service.ExcelCharacterColorService;
import com.td.Dawa.game.excelcharactercolor.vo.ExcelCharacterColorClientVo;
import com.td.Dawa.game.excelcharactercreate.pojo.ExcelCharacterCreate;
import com.td.Dawa.game.excelcharactercreate.service.ExcelCharacterCreateService;
import com.td.Dawa.game.excelcharacterlevel.pojo.ExcelCharacterLevel;
import com.td.Dawa.game.excelcharacterlevel.service.ExcelCharacterLevelService;
import com.td.Dawa.game.excelcharacterlevel.vo.ExcelCharacterLevelVo;
import com.td.Dawa.game.excelresources.pojo.ExcelResources;
import com.td.Dawa.game.excelresources.service.ExcelResourcesService;
import com.td.Dawa.game.excelresources.vo.ExcelResourcesClientVo;
import com.td.Dawa.util.CopyUtil;
import com.td.Dawa.util.ProbabilityIntervalUtil;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.expression.function.BasicFunctionExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
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 javax.persistence.criteria.Expression;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
@Slf4j
public class ComCharactersServiceImpl extends CommonServiceImpl<ComCharactersVo, ComCharacters, Integer> implements ComCharactersService {

    @PersistenceContext
    private EntityManager em;
    @Autowired
    private ComCharactersRepository comCharactersRepository;

    @Autowired
    private ExcelCharacterAttriRepository excelCharacterAttriRepository;

    /**
     * excel表service
     */
    @Autowired
    private ExcelCharacterCreateService excelCharacterCreateService;

    @Autowired
    private ExcelCharacterAttriService excelCharacterAttriService;

    @Autowired
    private ExcelCharacterLevelService excelCharacterLevelService;

    @Autowired
    private ExcelCharacterColorService excelCharacterColorService;

    @Autowired
    private ExcelResourcesService excelResourcesService;


    @Override
    public List<ComCharactersRandomVo> randomRoleByNumber(Integer number) {
        Specification<ExcelCharacterAttri> specification = (root, query, cb) -> {
            //Predicate pd = cb.and(cb.equal(root.get("title"), "测试题"));
            Expression<Double> e = new BasicFunctionExpression<>(
                    (CriteriaBuilderImpl) cb, Double.class, "rand"
            );
            query.orderBy(cb.desc(e));
            return null;
        };
        //1.获取了number 数量的 roleType todo 可加入内存
        List<ExcelCharacterAttri> excelCharacterAttrList = excelCharacterAttriRepository.findAll(specification, PageRequest.of(0, number)).toList();
        //2.根据roleType分类
        List<ComCharactersRandomVo> characters = new ArrayList<>();
        //3.查询role表全部数据
        //List<Integer> roleIds = excelCharacterAttrList.stream().map(e -> e.getRoleType()).collect(Collectors.toList());
        for (ExcelCharacterAttri excelCharacterAttr : excelCharacterAttrList) {
            ComCharactersRandomVo character = new ComCharactersRandomVo();
            character.setRoleId(excelCharacterAttr.getId());
            character.setRoleType(excelCharacterAttr.getRoleType());
            character.setAction(excelCharacterAttr.getAction());
            character.setInteractive(excelCharacterAttr.getInteractive());
            characters.add(character);
        }
        return characters;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ComCharactersClientVo addRole(ExcelCharacterAttriVo _attr, String userId) {

        Integer roleType = _attr.getRoleType();//todo 暂时用属性表里面的roleType
        //1.添加一个角色
        ComCharacters comCharacters = new ComCharacters();
        comCharacters.setUserId(userId);
        comCharacters.setRoleId(_attr.getId()); //用属性的id来设置roleId
        comCharacters.setRoleType(roleType);
        ////力量
        //Double _powerDouble = new Random().nextDouble() * (_attr.getStartPowerLimitUpper() - _attr.getStartPowerLimitLower()) + _attr.getStartPowerLimitLower();
        //comCharacters.setPower(_powerDouble.intValue());
        ////智力(智慧)
        //Double _intelligenceDouble = new Random().nextDouble() * (_attr.getStartWisdomLimitUpper() - _attr.getStartWisdomLimitLower()) + _attr.getStartWisdomLimitLower();
        //comCharacters.setIntelligence(_intelligenceDouble.intValue());
        ////技巧
        //Double _skillsDouble = new Random().nextDouble() * (_attr.getStartSkillLimitUpper() - _attr.getStartSkillLimitLower()) + _attr.getStartSkillLimitLower();
        //comCharacters.setSkills(_skillsDouble.intValue());

        //随机一个力量值，添加到后面的属性上
        comCharacters.setRandom(_attr.getRandomAttr());
        //力量
        Double _random1 = new Random().nextDouble() * _attr.getRandomAttr();
        Double _powerDouble = _random1 + _attr.getStartPowerLimitLower();
        comCharacters.setPower(_powerDouble.intValue());
        //智力(智慧)
        Double _random2 = new Random().nextDouble() * _attr.getRandomAttr();
        Double _intelligenceDouble = _random2 + _attr.getStartWisdomLimitLower();
        comCharacters.setIntelligence(_intelligenceDouble.intValue());
        //技巧
        Double _random3 = new Random().nextDouble() * _attr.getRandomAttr();
        Double _skillsDouble = _random3 + _attr.getStartSkillLimitLower();
        comCharacters.setSkills(_skillsDouble.intValue());

        comCharacters.setProfessional(0);//这里不区分职业，直接记录一个默认值，进行队伍配置时候，设置一个 1,2,3,4(挖矿，勘探，运输，伐木)
        comCharacters.setWorkPos(0);//记录一个默认没有位置
        comCharacters.setAction(_attr.getAction());
        comCharacters.setInteractive(_attr.getInteractive());
        comCharacters.setState(0);

        List<ExcelCharacterLevel> levelList = excelCharacterLevelService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_CHARACTER_LEVEL.getMessage());

        //设置经验和等级
        comCharacters.setExp(levelList.get(0).getExp());
        comCharacters.setLevel(levelList.get(0).getId());

        //随机生成一套model
        List<String> colorIdList = new ArrayList<>();

        //生成配件
        List<ComCharactersResourcesVo> _genList = generateCharacterModels();
        List<String> modelList = _genList.stream().map(e -> {
            colorIdList.add(e.getColorIds());
            return e.getArtId().toString();
        }).collect(Collectors.toList());

        comCharacters.setModelId(String.join("|", modelList));
        //记录颜色id
        comCharacters.setModelColor(String.join("|", colorIdList));

        comCharacters.setCreateTime(DateUtil.date());
        comCharacters.setUpdateTime(DateUtil.date());
        comCharacters = comCharactersRepository.saveAndFlush(comCharacters);
        //再存储一次id，根据当前生成的角色自增id来作为名字
        comCharacters.setName(comCharacters.getId().toString());
        comCharactersRepository.save(comCharacters);

        ComCharactersClientVo clientVo = CopyUtil.copy(comCharacters, ComCharactersClientVo.class);
        //设置第二级的升级经验
        ExcelCharacterLevel excelCharacterLevel = levelList.get(1) ;//2级
        clientVo.setLevelUpExp(excelCharacterLevel.getExp());

        clientVo.setSubResourcesClientList(_genList);

        return clientVo;
    }


    @Override
    public ComCharacters findByRoleId(Integer roleId) {
        return comCharactersRepository.findByRoleId(roleId).orElse(null);
    }

    /**
     * 根据类型返回对应的排名
     * 相同条件按创建时间处理
     * @param userId
     * @param attribute
     * @return
     */
    @Override
    public List<ComCharactersClientVo> findByProfessionalSort(String userId, Integer attribute) {
        String _properties = "power";//默认power排序
        if (attribute.equals(GameEnum.PRO_POWER.getValue())) {
            _properties = "power";
        } else if (attribute.equals(GameEnum.PRO_INTELLIGENCE.getValue())) {
            _properties = "intelligence";
        } else if (attribute.equals(GameEnum.PRO_SKIlLS.getValue())) {
            _properties = "skills";
        } else if (attribute.equals(3)) {
            //等级排序
            _properties = "level";
        }
        List<Sort.Order> sortOrder = new ArrayList<>();
        sortOrder.add(new Sort.Order(Sort.Direction.DESC, _properties));
        sortOrder.add(new Sort.Order(Sort.Direction.ASC,"createTime"));
        List<ComCharacters> comCharactersList = comCharactersRepository.findAllByUserId(userId, Sort.by(sortOrder));
        List<ComCharactersClientVo> comCharactersClientVos = comCharactersList.stream().map(e -> {
            ComCharactersClientVo comCharactersClientVo = CopyUtil.copy(e, ComCharactersClientVo.class);
            comCharactersClientVo = addSubResourcesClientListToVO(comCharactersClientVo, e.getModelId(), e.getModelColor());
            //获取当前的升级等级
            ExcelCharacterLevel _levelUpExp = excelCharacterLevelService.getNextLevelInfo(comCharactersClientVo.getLevel());
            comCharactersClientVo.setLevelUpExp(_levelUpExp.getExp());
            return comCharactersClientVo;
        }).collect(Collectors.toList());
        return comCharactersClientVos;
    }


    @Override
    public List<ComCharacters> findByRoleIdIn(Integer[] ids) {
        return comCharactersRepository.findByIdIn(ids, Sort.by(Sort.Direction.ASC, "id"));
    }

    /**
     * 生成 7个配件,颜色，位置
     *
     * @return
     */
    private List<ComCharactersResourcesVo> generateCharacterModels() {
        //全部颜色,并计算两个主副颜色
        List<ExcelCharacterColor> _allColors = excelCharacterColorService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_CHARACTER_COLOR.getMessage());
        //颜色类型（0，旧颜色，1花纹、耳朵、尾巴、嘴巴、轮廓主色颜色预设，2内耳预制色，3眉毛预制色，4眼睛颜色预制色）
        List<ExcelCharacterColor> _mainColors = _allColors.stream().filter(e->e.getType().equals(1)).collect(Collectors.toList());//取颜色1 为主颜色
        ExcelCharacterColor _AColor = _mainColors.get((int) (Math.random() * _mainColors.size())); //A主色
        List<ExcelCharacterColor> _bColorList = _mainColors.stream().filter(e -> !e.getId().equals(_AColor.getId())).collect(Collectors.toList());
        ExcelCharacterColor _BColor = _bColorList.get((int) (Math.random() * _bColorList.size()));//不与A重复的花色B副色
        //生产和资源
        List<ExcelCharacterCreate> _allCreates = excelCharacterCreateService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_CHARACTER_CREATE.getMessage());
        List<ExcelResources> _allResources = excelResourcesService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_RESOURCES.getMessage());
        //获取模型资源
        List<ExcelResources> roleResources = _allResources.stream().filter(e -> e.getArtType().equals(5)).collect(Collectors.toList());
        List<Integer> roleArtIds = roleResources.stream().map(ExcelResources::getArtId).collect(Collectors.toList());
        //输出对象list
        List<ComCharactersInfoVo> infoList = new ArrayList<>();
        List<ExcelCharacterCreate> _currentCharacters = new ArrayList<>();
        //1.生成瞳孔
        //权重计算，当前有20个权重1,9个权重6,4个权重5，加起来值是100
        List<ExcelCharacterCreate> pupilAll = _allCreates.stream().filter(e -> e.getPosition().equals(1)).collect(Collectors.toList());
        //ExcelCharacterCreate pupil = pupilAll.get((int) (Math.random() * pupilAll.size()));
        ExcelCharacterCreate pupil = ProbabilityIntervalUtil.getRolePos(pupilAll);
        //左右瞳孔 todo 可能需要颜色区分
        //_currentCharacters.add(pupil);
        //_currentCharacters.add(pupil);
        //瞳孔 独立色
        List<ExcelCharacterColor> _pupilColors = _allColors.stream().filter(e->e.getType().equals(4)).collect(Collectors.toList());//取颜色4 为眼睛颜色
        ExcelCharacterColor _pupilColor = _pupilColors.get((int) (Math.random() * _pupilColors.size()));
        infoList.add(new ComCharactersInfoVo(pupil, _pupilColor, false));
        infoList.add(new ComCharactersInfoVo(pupil, _pupilColor, true));

        //2.生成耳朵
        List<ExcelCharacterCreate> earsAll = _allCreates.stream().filter(e -> e.getPosition().equals(2)).collect(Collectors.toList());
        ExcelCharacterCreate ears = ProbabilityIntervalUtil.getRolePos(earsAll);// earsAll.get((int) (Math.random() * earsAll.size()));
        //_currentCharacters.add(ears);
        //_currentCharacters.add(ears);
        //内耳颜色，设置为副色
        List<ExcelCharacterColor> _earsColors = _allColors.stream().filter(e->e.getType().equals(2)).collect(Collectors.toList());//取颜色2 为内耳颜色
        ExcelCharacterColor _earsColor = _earsColors.get((int) (Math.random() * _earsColors.size()));
        //A色一致
        infoList.add(new ComCharactersInfoVo(ears, _AColor,_earsColor,false));
        infoList.add(new ComCharactersInfoVo(ears, _AColor,_earsColor, true));
        //3.生成眉毛
        List<ExcelCharacterCreate> eyebrowAll = _allCreates.stream().filter(e -> e.getPosition().equals(3)).collect(Collectors.toList());
        ExcelCharacterCreate eyebrow = ProbabilityIntervalUtil.getRolePos(eyebrowAll);// eyebrowAll.get((int) (Math.random() * eyebrowAll.size()));
        //_currentCharacters.add(eyebrow);
        //_currentCharacters.add(eyebrow);
        List<ExcelCharacterColor> _eyeColors = _allColors.stream().filter(e->e.getType().equals(3)).collect(Collectors.toList());//取颜色3 为眉毛颜色
        ExcelCharacterColor _eyeColor = _eyeColors.get((int) (Math.random() * _eyeColors.size()));
        infoList.add(new ComCharactersInfoVo(eyebrow, _eyeColor, false));
        infoList.add(new ComCharactersInfoVo(eyebrow, _eyeColor, true));
        //4.生成吻部
        List<ExcelCharacterCreate> snoutAll = _allCreates.stream().filter(e -> e.getPosition().equals(4)).collect(Collectors.toList());
        ExcelCharacterCreate snout = ProbabilityIntervalUtil.getRolePos(snoutAll);//snoutAll.get((int) (Math.random() * snoutAll.size()));
        //_currentCharacters.add(snout);
        //独立色
        ExcelCharacterColor _snoutColor = _mainColors.get((int) (Math.random() * _mainColors.size()));
        infoList.add(new ComCharactersInfoVo(snout, _snoutColor));
        //5.生成花纹
        List<ExcelCharacterCreate> decorativePatternAll = _allCreates.stream().filter(e -> e.getPosition().equals(5)).collect(Collectors.toList());
        ExcelCharacterCreate decorativePattern = ProbabilityIntervalUtil.getRolePos(decorativePatternAll); // decorativePatternAll.get((int) (Math.random() * decorativePatternAll.size()));
        //_currentCharacters.add(decorativePattern);
        infoList.add(new ComCharactersInfoVo(decorativePattern, _AColor, _BColor));

        //6.生成轮廓
        List<ExcelCharacterCreate> outLineAll = _allCreates.stream().filter(e -> e.getPosition().equals(6)).collect(Collectors.toList());
        ExcelCharacterCreate outLine = ProbabilityIntervalUtil.getRolePos(outLineAll);//outLineAll.get((int) (Math.random() * outLineAll.size()));
        //_currentCharacters.add(outLine);
        //独立色
        ExcelCharacterColor _outLineColor = _mainColors.get((int) (Math.random() * _mainColors.size()));
        infoList.add(new ComCharactersInfoVo(outLine, _outLineColor));
        //7.生成尾巴
        List<ExcelCharacterCreate> tailAll = _allCreates.stream().filter(e -> e.getPosition().equals(7)).collect(Collectors.toList());
        ExcelCharacterCreate tail = ProbabilityIntervalUtil.getRolePos(tailAll);//tailAll.get((int) (Math.random() * tailAll.size()));
        //_currentCharacters.add(tail);
        //独立色
        ExcelCharacterColor _tailColor = _mainColors.get((int) (Math.random() * _mainColors.size()));
        //主副色。主色与A色一致，副色为独立色
        infoList.add(new ComCharactersInfoVo(tail, _AColor, _tailColor));

        //拿到当前对应的resources 资源
        List<ComCharactersInfoVo> resourcesList = infoList.stream().map(_res -> {
            ExcelResources excelResources = roleResources.get(roleArtIds.indexOf(_res.getSubCreate().getModel()));
            _res.setSubResources(excelResources);
            return _res;
        }).collect(Collectors.toList());


        //对应资源
        List<ComCharactersResourcesVo> resourcesList2 = resourcesList.stream().map(_res -> {
            ComCharactersResourcesVo excelResourcesClientVo = new ComCharactersResourcesVo();
            excelResourcesClientVo = CopyUtil.copy(_res.getSubResources(), ComCharactersResourcesVo.class);
            excelResourcesClientVo.setPosition(_res.getSubCreate().getPosition());
            excelResourcesClientVo.setCharacterColor(CopyUtil.copy(_res.getSubPrimaryColor(), ExcelCharacterColorClientVo.class));
            excelResourcesClientVo.setNote(_res.getSubResources().getNote());
            if (_res.getSubSecondaryColor() != null) {
                excelResourcesClientVo.setCharacterSecondaryColor(CopyUtil.copy(_res.getSubSecondaryColor(), ExcelCharacterColorClientVo.class));
                //如果有两个颜色id这记录
                excelResourcesClientVo.setColorIds(_res.getSubPrimaryColor().getId() + "," + _res.getSubSecondaryColor().getId());
            } else {
                excelResourcesClientVo.setColorIds(_res.getSubPrimaryColor().getId().toString());
            }
            excelResourcesClientVo.setIsTheRight(_res.getIsTheRight());
            return excelResourcesClientVo;
        }).collect(Collectors.toList());

        return resourcesList2;
    }

    /**
     * 查询子配件,设置到 ComCharactersClientVo 里面
     *
     * @param comCharactersClientVo
     * @param _modelIdStr
     * @return
     */
    @Override
    public ComCharactersClientVo addSubResourcesClientListToVO(ComCharactersClientVo comCharactersClientVo, String _modelIdStr, String _modelColorStr) {
        Integer[] _modelIdArray = Convert.toIntArray(_modelIdStr.split("\\|"));
        List<ExcelCharacterColor> allColorList = excelCharacterColorService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_CHARACTER_COLOR.getMessage());
        List<Integer> allColorIdList = allColorList.stream().map(ExcelCharacterColor::getId).collect(Collectors.toList());
        // 1,2|主，副颜色
        List<String> _colorList = Arrays.asList(_modelColorStr.split("\\|"));
        List<String> _primaryColorList = new ArrayList<>();
        List<String> _secondaryColorList = new ArrayList<>();
        _colorList.stream().map(e -> {
            String[] _colorIds = e.split(",");
            if (_colorIds.length >= 2) {
                _primaryColorList.add(_colorIds[0]);
                _secondaryColorList.add(_colorIds[1]);
            } else {
                _primaryColorList.add(_colorIds[0]);
                _secondaryColorList.add("");
            }

            return e;
        }).collect(Collectors.toList());
        List<ExcelCharacterColor> allPrimaryColors = _primaryColorList.stream().map(e -> allColorList.get(allColorIdList.indexOf(Integer.parseInt(e)))).collect(Collectors.toList());
        List<ExcelCharacterColor> allSecondaryColors = new ArrayList<>();
        for (String id : _secondaryColorList) {
            if (StringUtils.hasText(id)&&allColorIdList.contains(Integer.parseInt(id))) {
                ExcelCharacterColor _color = allColorList.get(allColorIdList.indexOf(Integer.parseInt(id)));
                allSecondaryColors.add(_color);
            }else{
                allSecondaryColors.add(null);
            }
        }
        //查询position
        List<ExcelCharacterCreate> _genList = excelCharacterCreateService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_CHARACTER_CREATE.getMessage());
        List<Integer> characterModelIdList = _genList.stream().map(ExcelCharacterCreate::getModel).collect(Collectors.toList());
        List<ExcelResources> allResourcesList = excelResourcesService.getListFromCache(GameEnum.REDIS_KEY_EXCEL_RESOURCES.getMessage());
        List<Integer> allResourcesArtIdList = allResourcesList.stream().map(ExcelResources::getArtId).collect(Collectors.toList());
        List<ComCharactersResourcesVo> resourcesList = new ArrayList<>();
        for(int i = 0;i<_modelIdArray.length;i++){
            Integer ids = _modelIdArray[i];
            Integer currentIndex = i+1;
            ExcelResources excelResources =  allResourcesList.get(allResourcesArtIdList.indexOf(ids));
            ExcelCharacterCreate excelCharacterCreate = _genList.get(characterModelIdList.indexOf(ids));
            ComCharactersResourcesVo excelResourcesClientVo = CopyUtil.copy(excelResources, ComCharactersResourcesVo.class);
            //简单按顺序区分左右，通常第一个就是左边
            switch (currentIndex) {
                case 1:
                case 3:
                case 5:
                    excelResourcesClientVo.setIsTheRight(false);
                    break;
                case 2:
                case 4:
                case 6:
                    excelResourcesClientVo.setIsTheRight(true);
                    break;
            }
            excelResourcesClientVo.setNote(excelResources.getNote());
            excelResourcesClientVo.setColorIds(_colorList.get(i));
            excelResourcesClientVo.setPosition(excelCharacterCreate.getPosition());
            excelResourcesClientVo.setCharacterColor(CopyUtil.copy(allPrimaryColors.get(i), ExcelCharacterColorClientVo.class));
            if (allSecondaryColors.get(i) != null) {
                excelResourcesClientVo.setCharacterSecondaryColor(CopyUtil.copy(allSecondaryColors.get(i), ExcelCharacterColorClientVo.class));
            }
            resourcesList.add(excelResourcesClientVo);
        }
        comCharactersClientVo.setSubResourcesClientList(resourcesList);
        return comCharactersClientVo;
    }
}
