package com.friday.custody.service.basicService.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.friday.custody.dao.TenantEscrowAuthorizationInfoDao;
import com.friday.custody.dto.TenantEscrowAuthorizationInfoDto;
import com.friday.custody.dto.TenantInfoDto;
import com.friday.custody.entity.TenantEscrowAuthorizationInfoEntity;
import com.friday.custody.enums.RetCodeEnum;
import com.friday.custody.exception.RRException;
import com.friday.custody.req.TenantEscrowAuthorizationInfoReq;
import com.friday.custody.service.basicService.DataDictionaryTrustService;
import com.friday.custody.service.basicService.TenantEscrowAuthorizationInfoService;
import com.friday.custody.service.trustService.OutsourceService;
import com.friday.custody.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;


@Service("tenantEscrowAuthorizationInfoService")
@Slf4j
public class TenantEscrowAuthorizationInfoServiceImpl extends ServiceImpl<TenantEscrowAuthorizationInfoDao, TenantEscrowAuthorizationInfoEntity> implements TenantEscrowAuthorizationInfoService {

    @Value(value = "${file.parentPath.realPath}")
    private String realPath;
    @Value(value = "${file.parentPath.AuthorizationFile}")
    private String AuthorizationFile;

    @Autowired
    private OutsourceService outsourceService;

    @Autowired
    private TenantEscrowAuthorizationInfoDao tenantEscrowAuthorizationInfoDao;

    @Resource(name = "initTenantDataThreadPool")
    private ExecutorService initTenantDataThreadPool;

    @Autowired
    private DataDictionaryTrustService dataDictionaryTrustService;

    private static final Object createFilePathLock = new Object();

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R addEscrowAuthorization(String tenantName, TenantEscrowAuthorizationInfoDto dto) {
        String dtoInfo = tenantName + " : " + dto.getTrustNo() + " : " + dto.getAppKey();
        log.info("保存授权信息开始...{}", dtoInfo);
        try {
            TenantEscrowAuthorizationInfoEntity entity = new TenantEscrowAuthorizationInfoEntity();
            entity.setTenantName(tenantName);
            entity.setContactPerson(dto.getContactPerson());
            entity.setTrustNo(dto.getTrustNo());
            entity.setAppKey(dto.getAppKey());
            entity.setAppSecret(dto.getAppSecret());
            entity.setCompanyId(dto.getCompanyId());
            entity.setFilePath(saveFiles(dto, dto.getFiles()));
            entity.setCreateTime(new Date());
            entity.setUpdateTime(new Date());
            if (baseMapper.insert(entity) == 1) {
                log.info("保存授权信息成功：{}", dtoInfo);
                return R.ok("保存授权信息成功！");
            }
        } catch (RRException e) {
            throw e;
        } catch (Exception e) {
            log.error("保存授权信息失败：", e);
            if (e.getMessage().contains("unique_authorization")) {
                throw new RRException(RetCodeEnum.OPERATION_ERROR.getCode(), "每个租户每个联系人对同一个托管方，只能授权一次！");
            }
        }
        throw new RRException(RetCodeEnum.SYS_ERROR.getCode(), "保存授权信息失败！");
    }

    /**
     * 保存上传的文件
     * @param dto
     * @param files
     * @return
     */
    private String saveFiles(TenantEscrowAuthorizationInfoDto dto, MultipartFile[] files) {
        if (files == null || files.length == 0) {
            return null;
        }
        String filePath = realPath + AuthorizationFile + "/" + dto.getTenantName() + "/" + dto.getTrustNo() + "/" + dto.getContactPerson() + "/";
        try {
            File dirFile = new File(filePath);
            if (!dirFile.exists()) {
                synchronized (createFilePathLock) {
                    if (!dirFile.exists()) {
                        if (!dirFile.mkdirs()) {
                            log.error("创建授权文件目标文件夹失败：{}",filePath);
                            throw new RRException(RetCodeEnum.SYS_ERROR.getCode(),"保存授权文件失败！");
                        }
                    }
                }
            }
            for (MultipartFile file : files) {
                if (file == null || StringUtils.isBlank(file.getOriginalFilename())) {
                    continue;
                }
                String fileName = filePath + file.getOriginalFilename();
                log.info("fillTheDirectory : fileName: " + fileName);
                File desFile = new File(fileName);
                file.transferTo(desFile);
            }
            //设置文件父路径
            dto.setFilePath(filePath);
            return filePath;
        } catch (IOException e) {
            log.error("保存文件失败",e);
            throw new RRException(RetCodeEnum.SYS_ERROR.getCode(), "保存文件失败！");

        }
    }

    @Override
    public R<List<TenantEscrowAuthorizationInfoDto>> queryAuthorizations() {
        List<TenantEscrowAuthorizationInfoDto> dtos = null;
        try {
            List<TenantEscrowAuthorizationInfoEntity> entities = baseMapper.selectList(new QueryWrapper<>());
            //entity转dto
            if (!CollectionUtils.isEmpty(entities)) {
                dtos = entities.stream().map((entity) -> TenantEscrowAuthorizationInfoDto.builder()
                        .id(entity.getId())
                        .tenantName(entity.getTenantName())
                        .contactPerson(entity.getContactPerson())
                        .trustNo(entity.getTrustNo())
                        .appKey(entity.getAppKey())
                        .appSecret(entity.getAppSecret())
                        .companyId(entity.getCompanyId())
                        .filePath(entity.getFilePath())
                        .version(entity.getVersion())
                        .build()).collect(Collectors.toList());
            }
        } catch (Exception e) {
            log.error("queryAuthorizations:", e);
        }
        return new R<List<TenantEscrowAuthorizationInfoDto>>("查询成功！").setData(dtos);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R addEscrowAuthorizations(String tenantName, TenantInfoDto tenantInfoDto, List<TenantEscrowAuthorizationInfoReq> tenantEscrowAuthorizationInfoReqs) {
        log.info("批量授权开始{}", tenantEscrowAuthorizationInfoReqs);
        try {
            List<TenantEscrowAuthorizationInfoEntity> entityList = new ArrayList<>();
            tenantEscrowAuthorizationInfoReqs.forEach(req -> {
                //校验参数
                validateParam(req);
                //req封装成entity
                TenantEscrowAuthorizationInfoEntity entity = new TenantEscrowAuthorizationInfoEntity();
                entity.setTenantName(tenantName);
                entity.setAppKey(req.getAppKey());
                entity.setAppSecret(req.getAppSecret());
                entity.setTrustNo(req.getTrustNo());
                entity.setContactPerson(tenantInfoDto.getContactPerson());
                entity.setFilePath(req.getFilePath());
                entity.setCompanyId(req.getCompanyId());
                entity.setRemark(req.getRemark());
                entity.setCreateTime(new Date());
                entity.setUpdateTime(new Date());
                entityList.add(entity);
            });
            //批量添加授权信息
            int i = baseMapper.insertBatch(entityList);
            if (i > 0) {
                log.info("保存授权信息成功，{}", entityList);
                initData(entityList);
            }
            return R.ok("保存授权信息成功！");
        } catch (RRException rre) {
            log.error("批量添加授权信息失败！", rre.getMsg());
            return R.error(rre.getMsg());
        } catch (Exception e) {
            log.error("托管授权失败！", e);
            return R.error("授权失败！");
        }
    }

    public void initData(List<TenantEscrowAuthorizationInfoEntity> entityList) {
            //如果成功 则调用初始化数据接口
        List<TenantEscrowAuthorizationInfoDto> authorizationInfoDtoList = new ArrayList<>();
        entityList.forEach(entity -> {
            TenantEscrowAuthorizationInfoDto authorizationInfoDto = new TenantEscrowAuthorizationInfoDto().builder()
                    .tenantName(entity.getTenantName())
                    .trustNo(entity.getTrustNo())
                    .appKey(entity.getAppKey())
                    .appSecret(entity.getAppSecret())
                    .companyId(entity.getCompanyId())
                    .contactPerson(entity.getContactPerson())
                    .filePath(entity.getFilePath())
                    .remark(entity.getRemark())
                    .build();
            authorizationInfoDtoList.add(authorizationInfoDto);
        });
        CompletableFuture.supplyAsync(() -> {
            log.info("批量授权完成，开始初始化数据。。。。。。");
            outsourceService.initTenantData(authorizationInfoDtoList);
            return null;
        }, initTenantDataThreadPool);
    }
    private void validateParam(TenantEscrowAuthorizationInfoReq req) {
        RRException.isNotTrue(StringUtils.isBlank(req.getAppKey()), RetCodeEnum.PARAM_ERROR.getCode(), "appKey不能为空!");
        RRException.isNotTrue(StringUtils.isBlank(req.getAppSecret()), RetCodeEnum.PARAM_ERROR.getCode(), "appSecret不能为空!");
        //当托管人为25-招商证券时
        if (("25").equals(req.getTrustNo())) {
            RRException.isNotTrue(StringUtils.isBlank(req.getCompanyId()), RetCodeEnum.PARAM_ERROR.getCode(), "companyId不能为空!");
            RRException.isNotTrue(StringUtils.isBlank(req.getFilePath()), RetCodeEnum.PARAM_ERROR.getCode(), "filePath不能为空!");
        }
    }

    public TenantEscrowAuthorizationInfoDto queryAuthorizationByTrustNo(String trustNo) {
        return tenantEscrowAuthorizationInfoDao.getAuthorizationByTrustNo(trustNo);
    }
    public List<TenantEscrowAuthorizationInfoDto> queryAuthorizationByTrustNoAndTenantName(String tenantName,String trustNo) {
        return tenantEscrowAuthorizationInfoDao.getDtoByTenantNameTrustNo(tenantName,trustNo);
    }
    @Override
    public Set<String> queryAdminList() {
          return baseMapper.queryAdminList();
    }

    @Override
    public boolean updateByTenant(TenantEscrowAuthorizationInfoEntity authorizationInfo) {
        int updateCount = baseMapper.updateByTenant(authorizationInfo);
        if (updateCount != 0){
            return true;
        }
        return false;
    }

    @Override
    public List<TenantEscrowAuthorizationInfoEntity> queryData(String trustNo, String admin, String version) {
        List<TenantEscrowAuthorizationInfoEntity> entityList = baseMapper.queryList(trustNo, admin, version);
        if(ObjectUtil.isEmpty(entityList)){
            return null;
        }
        return entityList;
    }

    @Override
    public List<TenantEscrowAuthorizationInfoEntity> queryAuthorizationsByAdmin(String admin) {
        QueryWrapper<TenantEscrowAuthorizationInfoEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("tenant_name", admin);
        return tenantEscrowAuthorizationInfoDao.selectList(wrapper);
    }

    @Override
    public int deleteByTrust(String admin, String trustNo) {
        return baseMapper.deleteByTrustInfo(admin, trustNo);
    }

    public List<TenantEscrowAuthorizationInfoDto> queryAuthorizationsByTrustNo(String trustNo) {
        List<TenantEscrowAuthorizationInfoDto> dtos = new ArrayList<>();
        QueryWrapper<TenantEscrowAuthorizationInfoEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("trust_no", trustNo);
        List<TenantEscrowAuthorizationInfoEntity> entityList = baseMapper.selectList(queryWrapper);
        //entity转dto
        if (!CollectionUtils.isEmpty(entityList)) {
            dtos = entityList.stream().map((entity) -> TenantEscrowAuthorizationInfoDto.builder()
                    .id(entity.getId())
                    .tenantName(entity.getTenantName())
                    .contactPerson(entity.getContactPerson())
                    .trustNo(entity.getTrustNo())
                    .appKey(entity.getAppKey())
                    .appSecret(entity.getAppSecret())
                    .companyId(entity.getCompanyId())
                    .filePath(entity.getFilePath())
                    .build()).collect(Collectors.toList());
        }
        return dtos;
    }

    public boolean isExistAuthorization(String trustNo, String admin) {
        TenantEscrowAuthorizationInfoEntity entity = baseMapper.queryByTenant(trustNo, admin);
        if(ObjectUtil.isEmpty(entity)){
            return true;
        }
        return false;
    }
}