package com.ai.da.service.impl;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.ai.da.common.config.FileProperties;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.common.enums.SysFileLevel1TypeEnum;
import com.ai.da.common.enums.SysFileLevel2TypeEnum;
import com.ai.da.common.utils.*;
import com.ai.da.mapper.primary.StyleMapper;
import com.ai.da.mapper.primary.SysFileExtraMapper;
import com.ai.da.mapper.primary.SysFileMapper;
import com.ai.da.mapper.primary.entity.Style;
import com.ai.da.mapper.primary.entity.SysFile;
import com.ai.da.mapper.primary.entity.SysFileExtra;
import com.ai.da.model.vo.SysFileVO;
import com.ai.da.service.SysFileService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 服务实现类
 *
 * @author yanglei
 * @since 2022-09-30
 */
@Slf4j
@Service
public class SysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFile> implements SysFileService {
    @Resource
    private SysFileMapper sysFileMapper;
    @Resource
    private SysFileExtraMapper sysFileExtraMapper;
    @Resource
    private FileProperties fileProperties;
    @Resource
    private StyleMapper styleMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void initDefaultSysFile() {
        //删除已有的sysFile数据
        deleteAllSysFileData();
        //删除缓存
        clearCacheSysFileData();
        //读取linux环境系统图片地址
        List<File> allFile = FileUtil.getAllFile("/workspace/home/aida/file/sys");
        if (CollectionUtils.isEmpty(allFile)) {
            return;
        }
        Map<String, Long> idMap = initIdValueByLevel2Type();
        if (allFile.size() > 500) {
            AtomicInteger process = new AtomicInteger();
            //批量保存mysql 500条一次
            List<List<File>> fileList = Lists.partition(allFile, 500);
            fileList.forEach(list -> {
                log.info("初始化系统文件进度###次数###{}", process.getAndAdd(1));
                if (saveMany(initSysFile(list, idMap))) {
                    return;
                }
            });
            return;
        }
        saveMany(initSysFile(allFile, idMap));
    }

    private void clearCacheSysFileData() {
        LocalCacheUtils.clearAllMaxMinValueCache();
        LocalCacheUtils.clearAllSysFileCache();
        LocalCacheUtils.clearAllSysFileCacheByLevel2Type();
        log.info("初始化系统文件删除删除系统文件缓存完毕#####");
    }

    private void deleteAllSysFileData() {
        AtomicInteger process = new AtomicInteger();
        while (true) {
            // 分页数据
            QueryWrapper<SysFile> queryWrapper = new QueryWrapper<>();
            IPage<SysFile> page = this.getBaseMapper().selectPage(
                    new Page<>(1, 500), queryWrapper);
            if (CollectionUtils.isEmpty(page.getRecords())) {
                break;
            } else {
                List<Long> ids = page.getRecords().stream().map(SysFile::getId).collect(Collectors.toList());
                this.removeByIds(ids);
                log.info("初始化系统文件删除mysql数据进度###次数###{}", process.getAndAdd(1));
            }
        }
    }

    private List<SysFile> initSysFile(List<File> files, Map<String, Long> idMap) {
        List<SysFile> sysFiles = Lists.newArrayList();
        files.forEach(file -> {
            SysFile sysFile = new SysFile();
            sysFile.setCreateDate(new Date());
            String filePath = file.getAbsolutePath();
            sysFile.setLevel1Type(calculateLevel1Type(filePath));
            sysFile.setLevel2Type(calculateLevel2Type(filePath));
            sysFile.setId(getIdByLevel2Type(sysFile.getLevel2Type(), idMap));
            sysFile.setName(file.getName());
            try {
                FileInputStream inputStream = new FileInputStream(file);
                sysFile.setMd5(MD5Utils.encryptFile(inputStream));
            } catch (IOException ioException) {
                log.info("initSysFile 文件异常###{}", ExceptionUtil.getThrowableList(ioException));
                throw new BusinessException("initSysFile.ioException");
            }
            String linuxDomain = fileProperties.getLinuxDomain();
            if (!StringUtils.isEmpty(linuxDomain)) {
                //linux 系统
                String oldPath = fileProperties.getSys().getPath();
                sysFile.setUrl(filePath.replace(oldPath, linuxDomain));
            }
            sysFiles.add(sysFile);
        });
        return sysFiles;
    }

    private String calculateLevel1Type(String filePath) {
        String[] split = filePath.split("/");
        //一级目录
        SysFileLevel1TypeEnum sysFileLevel1Type = SysFileLevel1TypeEnum.uploadOf(split[split.length - 3]);
        if (Objects.nonNull(sysFileLevel1Type)) {
            return sysFileLevel1Type.getRealName();
        }
        return "";
    }

    private String calculateLevel2Type(String filePath) {
        String[] split = filePath.split("/");
        //一级目录
        SysFileLevel2TypeEnum sysFileLevel2Type = SysFileLevel2TypeEnum.uploadOf(split[split.length - 2]);
        if (Objects.nonNull(sysFileLevel2Type)) {
            return sysFileLevel2Type.getRealName();
        }
        return "";
    }

    private Long getIdByLevel2Type(String level2Type, Map<String, Long> IdMp) {
        Long id = IdMp.get(level2Type);
        Long newId = id + 1;
        IdMp.put(level2Type, newId);
        return newId;
    }

    private Map<String, Long> initIdValueByLevel2Type() {
        //每个类型分配100000 十万个位置
        Map<String, Long> idMap = Maps.newHashMap();
        // 0 到 100000
        idMap.put(SysFileLevel2TypeEnum.EARRINGS.getRealName(), 0L);
        // 100001  到 200000
        idMap.put(SysFileLevel2TypeEnum.HAIRSTYLE.getRealName(), 100000L);
        // 200001  到 300000
        idMap.put(SysFileLevel2TypeEnum.SHOES.getRealName(), 200000L);
        // 300001  到 400000
        idMap.put(SysFileLevel2TypeEnum.BLOUSE.getRealName(), 300000L);
        // 400001  到 500000
        idMap.put(SysFileLevel2TypeEnum.DRESS.getRealName(), 400000L);
        // 500001  到 600000
        idMap.put(SysFileLevel2TypeEnum.OUTWEAR.getRealName(), 500000L);
        // 600001  到 700000
        idMap.put(SysFileLevel2TypeEnum.SKIRT.getRealName(), 600000L);
        // 700001  到 800000
        idMap.put(SysFileLevel2TypeEnum.TROUSERS.getRealName(), 700000L);
        // 800001  到 900000
        idMap.put(SysFileLevel2TypeEnum.ICON.getRealName(), 800000L);
        // 900001  到 1000000
        idMap.put(SysFileLevel2TypeEnum.BAG.getRealName(), 900000L);
        // 1000001  到 1100000
        idMap.put(SysFileLevel2TypeEnum.BODY.getRealName(), 1000000L);
        return idMap;
    }

    @Override
    public Long getMaxIdByLevel2Type(String level2Type, String modelSex) {
        String key = "MAX_" + level2Type;
        Long maxId = LocalCacheUtils.getFileMaxMinValueCache(key);
        if (null == maxId) {
            maxId = maxId(level2Type, modelSex);
            LocalCacheUtils.setFileMaxMinValueCache(key, maxId);
        }
        return maxId;
    }

    @Override
    public Long getMinIdByLevel2Type(String level2Type, String modelSex) {
        String key = "MIN_" + level2Type;
        Long minId = LocalCacheUtils.getFileMaxMinValueCache(key);
        if (null == minId || minId == 0L) {
            minId = minId(level2Type, modelSex);
            LocalCacheUtils.setFileMaxMinValueCache(key, minId);
        }
        return minId;
    }

    @Override
    public SysFileVO getById(Long id) {
        SysFileVO sysFile = LocalCacheUtils.getSysFileCache(id);
        if (Objects.isNull(sysFile) || Objects.isNull(sysFile.getId())) {
            sysFile = CopyUtil.copyObject(sysFileMapper.selectById(id), SysFileVO.class);
            if (Objects.nonNull(sysFile)){
                LocalCacheUtils.setSysFileCache(id, sysFile);
            } else {
                return null;
            }
        }
        return sysFile;
    }

    @Override
    public List<SysFileVO> getByLevel2Type(String level2Type) {
        //校验
//        SysFileLevel2TypeEnum level2TypeEnum = SysFileLevel2TypeEnum.realNameOfPython(level2Type);
//        if(Objects.isNull(level2TypeEnum)){
//            throw new BusinessException("unknown level2Type "+level2Type);
//        }
        List<SysFileVO> cacheSysFileList = LocalCacheUtils.getSysFileCacheByLevel2Type(level2Type);
        if (CollectionUtils.isEmpty(cacheSysFileList)) {
            QueryWrapper<SysFile> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("level2_type", SysFileLevel2TypeEnum.ofPython());
            List<SysFileVO> sysFiles = CopyUtil.copyList(sysFileMapper.selectList(queryWrapper), SysFileVO.class);
            LocalCacheUtils.setSysFileCacheByLevel2Type(level2Type, sysFiles);
            return sysFiles;
        }
        return cacheSysFileList;
    }

    private Long maxId(String level2Type, String modelSex) {
        QueryWrapper<SysFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("level2_type", level2Type);
        queryWrapper.eq(!StringUtils.isEmpty(modelSex), "level3_type", modelSex);
        queryWrapper.select("max(id) as id ");
        SysFile sysFile = sysFileMapper.selectOne(queryWrapper);
        return sysFile.getId();
    }

    private Long minId(String level2Type, String modelSex) {
        QueryWrapper<SysFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("level2_type", level2Type);
        queryWrapper.eq(!StringUtils.isEmpty(modelSex), "level3_type", modelSex);
        queryWrapper.select("min(id) as id ");
        SysFile sysFile = sysFileMapper.selectOne(queryWrapper);
        return sysFile.getId();
    }

    private boolean saveMany(List<SysFile> sysFiles) {
        if (!this.saveBatch(sysFiles)) {
            throw new BusinessException("save.sysFile.failed");
        }
        return Boolean.TRUE;
    }

    @Override
    public List<SysFileVO> getByUrlList(List<String> urlList) {
        QueryWrapper<SysFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("url", urlList);
        return CopyUtil.copyList(sysFileMapper.selectList(queryWrapper), SysFileVO.class);
    }

    @Override
    public List<SysFile> getByIds(List<Long> ids) {
        QueryWrapper<SysFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", ids);
        return sysFileMapper.selectList(queryWrapper);
    }

    @Override
    public SysFile getOneBySex(Long styleId, String sex, String ageGroup) {
        Style style = new Style();
        if (styleId != null) {
            style = styleMapper.selectById(styleId);
        }
        QueryWrapper<SysFile> qw = new QueryWrapper<>();
        qw.lambda().eq(SysFile::getLevel1Type, "Models");
        qw.lambda().eq(SysFile::getLevel2Type, sex);

        QueryWrapper<SysFileExtra> sysFileExtraQW = new QueryWrapper<>();
        sysFileExtraQW.lambda().eq(SysFileExtra::getAgeGroup, ageGroup);
        Set<Long> collect = sysFileExtraMapper.selectList(sysFileExtraQW).stream().map(SysFileExtra::getSysId).collect(Collectors.toSet());
        if (!CollectionUtils.isEmpty(collect)) {
            qw.lambda().in(SysFile::getId, collect);
        }

        if (style.getId() != null) {
            qw.lambda().eq(SysFile::getLevel3Type, style.getName());
        }
        List<SysFile> sysFileList = sysFileMapper.selectList(qw);
        if (!CollectionUtils.isEmpty(sysFileList)) {
            return sysFileList.get(0);
        }
        return null;
    }

    @Override
    public SysFile getOneBySex(String styleName, String sex, String ageGroup) {
        QueryWrapper<SysFile> qw = new QueryWrapper<>();
        qw.lambda().eq(SysFile::getLevel1Type, "Models");
        qw.lambda().eq(SysFile::getLevel2Type, sex);

        QueryWrapper<SysFileExtra> sysFileExtraQW = new QueryWrapper<>();
        sysFileExtraQW.lambda().eq(SysFileExtra::getAgeGroup, ageGroup);
        Set<Long> collect = sysFileExtraMapper.selectList(sysFileExtraQW).stream().map(SysFileExtra::getSysId).collect(Collectors.toSet());
        if (!CollectionUtils.isEmpty(collect)) {
            qw.lambda().in(SysFile::getId, collect);
        }

        if (!StringUtils.isEmpty(styleName)) {
            qw.lambda().eq(SysFile::getLevel3Type, styleName);
        }
        List<SysFile> sysFileList = sysFileMapper.selectList(qw);
        if (!CollectionUtils.isEmpty(sysFileList)) {
            return sysFileList.get(0);
        }
        return null;
    }

    public static void main(String[] args) {
        Style style = new Style();
        if (Objects.nonNull(style)) {
            System.out.println("buxing");
        }
    }
}
