package com.yh.saas.plugin.clouddisk.service.impl;

import com.alipay.sofa.runtime.api.annotation.SofaReference;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.toolkit.StringUtils;
import com.winsea.svc.base.base.entity.CommonAppendix;
import com.winsea.svc.base.base.entity.CommonCompany;
import com.winsea.svc.base.base.entity.CommonTenant;
import com.winsea.svc.base.base.service.IAppendixService;
import com.winsea.svc.base.base.service.ICommonCompanyService;
import com.winsea.svc.base.base.service.ICommonTenantService;
import com.winsea.svc.base.base.util.AppendixWrapper;
import com.winsea.svc.base.base.util.ClientTypeChecker;
import com.winsea.svc.base.security.util.AuthSecurityUtils;
import com.yh.saas.common.support.util.IdGenerator;
import com.yh.saas.common.support.util.RegExUtils;
import com.yh.saas.common.support.util.query.QueryUtils;
import com.yh.saas.plugin.clouddisk.entity.DataManagerFileInfo;
import com.yh.saas.plugin.clouddisk.exception.DataManagerException;
import com.yh.saas.plugin.clouddisk.exception.DataManagerExceptionEnums;
import com.yh.saas.plugin.clouddisk.mapper.DataManagerFileMapper;
import com.yh.saas.plugin.clouddisk.service.IDataManagerFileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class DataManagerFileServiceImpl extends ServiceImpl<DataManagerFileMapper, DataManagerFileInfo> implements IDataManagerFileService {

    @SofaReference
    private ICommonCompanyService companyService;

    @SofaReference
    private ICommonTenantService tenantService;

    @Autowired
    private AppendixWrapper appendixWrapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @SofaReference
    private IAppendixService appendixService;

    //初始云盘大小
    private static final String INIT_CLOUD_DISK_SIZE = "10G";

    //内存计算单位
    private static final BigDecimal quantityUnit = new BigDecimal(1024);

    @Override
    @Transactional
    public void saveFile(List<String> files, DataManagerFileInfo dataManagerFileInfo) {
        if (CollectionUtils.isEmpty(files)) {
            throw new DataManagerException(DataManagerExceptionEnums.DATA_MANAGER_UPDATE_FILE_NULL_ERROR);
        }
        if (StringUtils.isEmpty(dataManagerFileInfo.getFolderId())) {
            throw new DataManagerException(DataManagerExceptionEnums.DATA_MANAGER_UPDATE_FOLDER_NULL_ERROR);
        }

        List<CommonAppendix> appendices = appendixService.selectList(new EntityWrapper<CommonAppendix>()
                .in(CommonAppendix.QueryFields.APPENDIX_ID, files));
        if (CollectionUtils.isEmpty(appendices)) {
            throw new DataManagerException(DataManagerExceptionEnums.DATA_MANAGER_NULL_APPENDIX);
        }
        List<String> appendixSizes = appendices.stream().map(CommonAppendix::getAppendixSize).collect(Collectors.toList());

        //更新到数据库的数据集合
        List<DataManagerFileInfo> dataManagerFileInfos = new ArrayList<>();
        //增加云盘剩余大小判断
        if (!testCloudDiskSize(dataManagerFileInfo.getCompId(), appendixSizes)) {
            throw new DataManagerException(DataManagerExceptionEnums.DATA_MANAGER_SURPLUS_SIZE);
        }

        for (CommonAppendix appendix : appendices) {
            DataManagerFileInfo fileInfo = new DataManagerFileInfo();
            if (checkFolderRepeatFile(dataManagerFileInfo.getFolderId(), appendix.getAppendixName().substring(0, appendix.getAppendixName().lastIndexOf(".")))) {
                throw new DataManagerException(DataManagerExceptionEnums.DATA_MANAGER_FILE_NAME_REPEAT);
            }

            fileInfo.setFileId(IdGenerator.generateUUID());
            fileInfo.setFilePath(dataManagerFileInfo.getFilePath());
            fileInfo.setAppendixId(appendix.getAppendixId());
            fileInfo.setFolderId(dataManagerFileInfo.getFolderId());
            fileInfo.setFileSize(appendix.getAppendixSize());
            fileInfo.setFileName(appendix.getAppendixName().substring(0, appendix.getAppendixName().lastIndexOf(".")));
            fileInfo.setCompId(dataManagerFileInfo.getCompId());
            fileInfo.setFileInfoType(appendix.getAppendixName().substring(appendix.getAppendixName().lastIndexOf(".")) + "文件");
            fileInfo.setSynchronizationFlag("0");

            dataManagerFileInfos.add(fileInfo);
        }
        this.insertBatch(dataManagerFileInfos);
    }

    @Override
    @Transactional
    public void removeAll(List<DataManagerFileInfo> dataManagerFileInfos) {
        for (DataManagerFileInfo dataManagerFileInfo : dataManagerFileInfos) {
            if (StringUtils.isEmpty(dataManagerFileInfo.getFilePath())) {
                continue;
            }
            new File(dataManagerFileInfo.getFilePath()).delete();
        }
        List<String> dataManagerFileIds = dataManagerFileInfos.stream().map(DataManagerFileInfo::getFileId).collect(Collectors.toList());
        this.deleteBatchIds(dataManagerFileIds);
    }

    @Override
    public Page<DataManagerFileInfo> findFileUnderFolder(DataManagerFileInfo dataManagerFileInfo) {
        dataManagerFileInfo.setCompId(AuthSecurityUtils.getCurrentUserInfo().getCompId());
        if (!StringUtils.isEmpty(dataManagerFileInfo.getUpdateTimeStart())) {
            dataManagerFileInfo.setUpdateTimeStart(dataManagerFileInfo.getUpdateTimeStart() + " 00:00:00");
        }

        if (!StringUtils.isEmpty(dataManagerFileInfo.getUpdateTimeEnd())) {
            dataManagerFileInfo.setUpdateTimeEnd(dataManagerFileInfo.getUpdateTimeEnd() + " 23:59:59");
        }

        Wrapper<DataManagerFileInfo> wrapper = QueryUtils.convertExampleToWrapper(dataManagerFileInfo);
        if (StringUtils.isEmpty(dataManagerFileInfo.getOrderColunm())) {
            wrapper.orderBy("CONVERT(file_name USING gbk)", true);
        }
        return this.selectPage(dataManagerFileInfo.getQueryPage(), wrapper);
    }

    @Override
    public void downFile(List<String> fileUrls, String zipName) {
        appendixWrapper.packAndDownloadUrlList(fileUrls, null, zipName);
    }

    @Override
    public void fileRename(String fileId, String fileName) {
        DataManagerFileInfo dataManagerFileInfo = this.selectById(fileId);
        //appendixService.rename(dataManagerFileInfo.getAppendixId(), fileName);
        dataManagerFileInfo.setFileName(fileName);
        //附件信息
        CommonAppendix appendix = appendixService.selectById(dataManagerFileInfo.getAppendixId());
        if(null != appendix){
            String fileType = appendix.getAppendixPath().substring(appendix.getAppendixPath().lastIndexOf("."));
            appendix.setAppendixName(fileName + fileType);
            appendixService.updateById(appendix);
        }
        dataManagerFileInfo.updateById();
    }

    @Override
    public List<String> findFileType(String compId) {
        List<DataManagerFileInfo> dataManagerFileInfos = this.selectList(new EntityWrapper<DataManagerFileInfo>()
                .eq(DataManagerFileInfo.QueryFields.COMP_ID, compId)
                .groupBy(DataManagerFileInfo.QueryFields.FILE_INFO_TYPE));
        return dataManagerFileInfos.stream().map(DataManagerFileInfo::getFileInfoType).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public void transferFolder(DataManagerFileInfo dataManagerFileInfo) {
        DataManagerFileInfo fileInfo = this.selectById(dataManagerFileInfo.getFileId());
        if (checkFolderRepeatFile(dataManagerFileInfo.getFolderId(), fileInfo.getFileName())) {
            throw new DataManagerException(DataManagerExceptionEnums.DATA_MANAGER_FILE_NAME_REPEAT);
        }
        dataManagerFileInfo.updateById();
    }

    @Override
    public void removeFolderFile(String folderId) {
        this.delete(new EntityWrapper<DataManagerFileInfo>().eq(DataManagerFileInfo.QueryFields.FOLDER_ID, folderId));
    }

    @Override
    public void updateRedisCloudDiskSize(String compId) {
        //获取租户
        CommonTenant tenant = getTenant(compId);
        if (null == tenant) {
            return;
        }
        //根据租户查询下面公司
        List<CommonCompany> commonCompanies = companyService.findTenantCompany(tenant.getTenantId());
        if (CollectionUtils.isEmpty(commonCompanies)) {
            return;
        }
        List<String> compIds = commonCompanies.stream().map(CommonCompany::getCompId).collect(Collectors.toList());
        //根据公司查询文件数量
        List<DataManagerFileInfo> fileInfos = this.selectList(new EntityWrapper<DataManagerFileInfo>().in(DataManagerFileInfo.QueryFields.COMP_ID, compIds));
        if (CollectionUtils.isEmpty(fileInfos)) {
            return;
        }
        //文件相加
        BigDecimal fileSize = new BigDecimal(0);
        for (DataManagerFileInfo fileInfo : fileInfos) {
            fileSize = fileSize.add(new BigDecimal(RegExUtils.getNumber(fileInfo.getFileSize())));
        }
        //替换云盘大小
        BigDecimal bigSize = new BigDecimal(transformationGKB(tenant.getCloudDiskSize()));
        // BigDecimal surplus = bigSize.subtract(fileSize);
        redisTemplate.opsForValue().set("cloudDiskSize:" + tenant.getTenantId(), fileSize.toString());
    }


    /**
     * 检测文件夹下是否有相同数据
     *
     * @param folderId 文件夹id
     * @param fileName 文件名称
     * @return 是否有重复的
     */
    private Boolean checkFolderRepeatFile(String folderId, String fileName) {
        List<DataManagerFileInfo> dataManagerFileInfos = this.selectList(new EntityWrapper<DataManagerFileInfo>()
                .eq(DataManagerFileInfo.QueryFields.FOLDER_ID, folderId)
                .eq(DataManagerFileInfo.QueryFields.FILE_NAME, fileName));

        return CollectionUtils.isNotEmpty(dataManagerFileInfos);
    }

    /**
     * 当redis 上没有剩余空间的时候,去数据库里去取所有文件开始计算大小
     *
     * @param compId 公司id
     * @return 返回BigDecimal 已使用大小
     */
    private BigDecimal calculationUsedSize(List<String> compId) {
        List<DataManagerFileInfo> dataManagerFileInfos = this.selectList(new EntityWrapper<DataManagerFileInfo>()
                .eq(DataManagerFileInfo.QueryFields.COMP_ID, compId)
                .groupBy(DataManagerFileInfo.QueryFields.FILE_SIZE));
        BigDecimal sum = new BigDecimal(0);
        List<String> fileSizes = dataManagerFileInfos.stream().map(DataManagerFileInfo::getFileSize).collect(Collectors.toList());
        for (String fileSize : fileSizes) {
            sum.add(new BigDecimal(fileSize));
        }
        return sum;
    }

    /**
     * 检测当前租户云盘剩余大小是否够存
     *
     * @param compId 公司大小
     * @return 是否能继续上传文件
     */
    private Boolean testCloudDiskSize(String compId, List<String> filesSize) {
        //事先判断是否是船端 (如果是船端就不进行计算云盘大小)
        if (ClientTypeChecker.isVesselTerminal()) {
            return true;
        }
        //获取当前租户剩余内存大小
        BigDecimal sum = getTenantSurplusCloudSize(compId);
        BigDecimal cloudSizeKb = new BigDecimal(sum.toString());

        //初始化
        BigDecimal fileSumSize = new BigDecimal(0);
        //获取当前所有文件内存
        for (String fileSize : filesSize) {
            if (StringUtils.isEmpty(fileSize)) {
                fileSumSize = fileSumSize.add(new BigDecimal(0));
            } else {
                fileSumSize = fileSumSize.add(new BigDecimal(RegExUtils.getNumber(fileSize)));
            }
        }
        return cloudSizeKb.intValue() >= fileSumSize.intValue();
    }

    /**
     * 获取租户剩余云盘大小
     *
     * @param compId 公司Id
     * @return 剩余大小
     */
    private BigDecimal getTenantSurplusCloudSize(String compId) {
        //查询租户
        CommonTenant tenant = getTenant(compId);
        if (null == tenant) {
            return null;
        }

        //获取redis 已使用大小
        String redisKey = "cloudDiskSize:" + tenant.getTenantId();
        String surplusCloudSize = redisTemplate.opsForValue().get(redisKey);
        BigDecimal sum;
        if (StringUtils.isEmpty(surplusCloudSize)) {
            List<CommonCompany> commonCompanies = companyService.findTenantCompany(tenant.getTenantId());
            if (CollectionUtils.isEmpty(commonCompanies)) {
                return null;
            }
            sum = calculationUsedSize(commonCompanies.stream().map(CommonCompany::getCompId).collect(Collectors.toList()));
        } else {
            sum = new BigDecimal(surplusCloudSize);
        }

        String cloudDiskSize;
        if (StringUtils.isEmpty(tenant.getCloudDiskSize())) {
            cloudDiskSize = INIT_CLOUD_DISK_SIZE;
        } else {
            cloudDiskSize = tenant.getCloudDiskSize();
        }

        //获取当前租户云盘大小计算(KB)
        BigDecimal cloudSizeKb = new BigDecimal((transformationGKB(cloudDiskSize)));
        return cloudSizeKb.subtract(sum);
    }

    /**
     * G 转换KB
     */
    private static String transformationGKB(String G) {
        return new BigDecimal(RegExUtils.getNumber(G)).multiply(quantityUnit).multiply(quantityUnit).toString();
    }

    /**
     * 获取租户
     *
     * @param compId 公司id
     * @return 租户对象
     */
    private CommonTenant getTenant(String compId) {
        CommonCompany commonCompany = companyService.findCompanyInfo(compId);
        return tenantService.selectById(commonCompany.getTenantId());
    }
}
