package com.microservices.zone.resource.service.impl;

import com.microservices.common.core.constant.HttpStatus;
import com.microservices.common.core.constant.SecurityConstants;
import com.microservices.common.core.enums.SystemRole;
import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.common.core.utils.PageUtils;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.core.web.page.GenericsTableDataInfo;
import com.microservices.common.datascope.annotation.DataScope;
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
import com.microservices.common.security.auth.AuthUtil;
import com.microservices.common.security.utils.SecurityUtils;
import com.microservices.system.api.RemoteFileService;
import com.microservices.system.api.RemoteUserService;
import com.microservices.system.api.domain.SysFileInfo;
import com.microservices.system.api.domain.SysUser;
import com.microservices.system.api.utils.FeignUtils;
import com.microservices.zone.common.service.IZoneSortService;
import com.microservices.zone.detail.domain.ZoneDetail;
import com.microservices.zone.detail.domain.ZoneSort;
import com.microservices.zone.detail.service.IZoneDetailService;
import com.microservices.zone.resource.domain.ZoneResource;
import com.microservices.zone.resource.domain.ZoneResourceToType;
import com.microservices.zone.resource.domain.ZoneResourceType;
import com.microservices.zone.resource.domain.vo.*;
import com.microservices.zone.resource.mapper.ZoneResourceMapper;
import com.microservices.zone.resource.mapper.ZoneResourceToTypeMapper;
import com.microservices.zone.resource.service.IZoneResourceDomainService;
import com.microservices.zone.resource.service.IZoneResourceService;
import com.microservices.zone.resource.service.IZoneResourceTypeService;
import com.microservices.zone.specialProject.service.IZoneSpecialProjectRelevancyService;
import com.microservices.zone.utils.ZoneConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 特色专区资源聚合Service业务层处理
 *
 * @author otto
 * @date 2023-06-27
 */
@Service
public class ZoneResourceServiceImpl implements IZoneResourceService {
    private static final Logger logger = LoggerFactory.getLogger(ZoneResourceServiceImpl.class);
    @Autowired
    private ZoneResourceMapper zoneResourceMapper;
    @Autowired
    private IZoneResourceTypeService zoneResourceTypeService;
    @Autowired
    private IZoneResourceDomainService zoneResourceDomainService;
    @Autowired
    private IZoneSortService zoneSortService;
    @Autowired
    private IZoneDetailService zoneDetailService;
    @Autowired
    private RemoteFileService remoteFileService;
    @Autowired
    private RemoteUserService remoteUserService;
    @Autowired
    private ZoneResourceToTypeMapper zoneResourceToTypeMapper;
    @Autowired
    private GitLinkRequestHelper gitLinkRequestHelper;
    @Autowired
    @Lazy
    private IZoneSpecialProjectRelevancyService zoneSpecialProjectRelevancyService;

    /**
     * 查询特色专区资源聚合
     *
     * @param id 特色专区资源聚合主键
     * @return 特色专区资源聚合
     */
    @Override
    public ZoneResource selectZoneResourceById(Long id) {
        ZoneResource zoneResource = zoneResourceMapper.selectZoneResourceById(id);
        if (zoneResource == null) {
            throw new ServiceException("该资源不存在或无权限访问(资源id[" + id + "])");
        }
        zoneDetailService.checkZoneDataScope(zoneResource.getZoneId());
        return zoneResource;
    }

    /**
     * 查询特色专区资源聚合列表
     *
     * @param zoneResourceSearch 特色专区资源聚合
     * @return 特色专区资源聚合
     */
    @Override
    @DataScope(deptAlias = "zr")
    public GenericsTableDataInfo<ZoneResourceDataVo> selectZoneResourceList(ZoneResource zoneResourceSearch) {
        List<ZoneResource> zoneResourceList = zoneResourceMapper.selectZoneResourceList(zoneResourceSearch);
        return PageUtils.toPage(zoneResourceList, this::zoneResourceToData);
    }

    private ZoneResourceDataVo zoneResourceToData(ZoneResource zoneResource) {
        ZoneResourceDataVo zoneResourceDataVo = zoneResource.toZoneResourceDataVo();
        int downloadCount = 0;
        if (StringUtils.isNotEmpty(zoneResource.getFileIds())) {
            List<SysFileInfo> sysFileInfoList = FeignUtils.getReturnData(
                    remoteFileService.getFileList(zoneResource.getFileIds())
            );
            if (sysFileInfoList != null) {
                List<ZoneResourceFileVo> zoneResourceFileVoList = sysFileInfoList
                        .stream()
                        .map(x -> {
                            ZoneResourceType zoneResourceType =
                                    zoneResourceTypeService.getResourceTypeByFileSuffix(zoneResource.getZoneId(), x.getFileSuffix());
                            return new ZoneResourceFileVo(zoneResourceType, x);
                        }).collect(Collectors.toList());
                zoneResourceDataVo.setFileList(zoneResourceFileVoList);
                downloadCount = sysFileInfoList.stream().mapToInt(SysFileInfo::getDownloadCount).sum();
            }
        }
        List<ZoneResourceToType> zoneResourceToTypes = zoneResourceToTypeMapper.selectResourceToTypeListByResourceId(zoneResource.getId());
        Long[] typeIds = zoneResourceToTypes.stream().map(ZoneResourceToType::getTypeId)
                .collect(Collectors.toList())
                .toArray(new Long[zoneResourceToTypes.size()]);
        ;
        zoneResourceDataVo.setTypeIds(typeIds);
        if (typeIds.length > 0) {
            List<ZoneResourceType> zoneResourceTypeList = zoneResourceTypeService.selectZoneResourceTypeListInTypeIds(typeIds);
            zoneResourceDataVo.setZoneResourceTypeList(zoneResourceTypeList);
        }
        if (StringUtils.isNotEmpty(zoneResource.getCreateBy())) {
            // 提供资源创建人相关信息
            SysUser createUser = FeignUtils.getReturnData(
                    remoteUserService.getSysUserByUserName(zoneResource.getCreateBy(), SecurityConstants.INNER)
            );
            if (createUser != null) {
                zoneResourceDataVo.setCreateUser(createUser.toSimpleSysUser(gitLinkRequestHelper.gitLinkUrl));
            }
        }
        zoneResourceDataVo.setDownloadCount(downloadCount);
        return zoneResourceDataVo;
    }

    private boolean resourceNeedAudit(ZoneDetail zoneDetail) {
        if (1 == zoneDetail.getResourceNeedAudit()) {
            boolean isOperator = AuthUtil.hasUserIdentity(zoneDetail.getDeptId(), SystemRole.ZONE_OPERATOR.getRoleKey());
            boolean isMember = AuthUtil.hasUserIdentity(zoneDetail.getDeptId(), SystemRole.ZONE_MEMBER.getRoleKey());
            if (isOperator || isMember) {
                return true;
            }
        }
        return false;
    }

    /**
     * 新增特色专区资源聚合
     *
     * @param zoneResourceInputVo 特色专区资源聚合
     * @return 结果
     */
    @Override
    public ZoneResourceDataVo insertZoneResource(ZoneResourceInputVo zoneResourceInputVo) {
        ZoneDetail zoneDetail = zoneDetailService.selectZoneDetailById(zoneResourceInputVo.getZoneId());
        checkNameInZone(zoneResourceInputVo.getZoneId(), zoneResourceInputVo.getName());
        zoneResourceDomainService.selectZoneResourceDomainById(zoneResourceInputVo.getDomainId());
        ZoneResource zoneResource = zoneResourceInputVo.toZoneResource();
        // 专区开启资源审核后，专区会员和专区运营人员新增资源都需要审核
        if (resourceNeedAudit(zoneDetail)) {
            zoneResource.setAuditStatus(ZoneConstants.RESOURCE_NOT_AUDIT);
        }
        zoneResource.setCreateTime(DateUtils.getNowDate());
        zoneResource.setCreateBy(SecurityUtils.getUsername());
        zoneResource.setDeptId(zoneDetail.getDeptId());
        Integer maxSort = zoneSortService.getMaxSort(zoneResourceInputVo.getZoneId(), ZoneResource.table_name);
        zoneResource.setSort(maxSort);
        zoneResourceMapper.insertZoneResource(zoneResource);
        if (StringUtils.isNotEmpty(zoneResourceInputVo.getFileIds())) {
            List<String> fileSuffixList = getAllFileSuffix(zoneResourceInputVo.getFileIds());
            List<ZoneResourceType> zoneResourceTypeList =
                    zoneResourceTypeService.selectZoneResourceTypeListBySuffixList(zoneResourceInputVo.getZoneId(), fileSuffixList);
            List<ZoneResourceToType> zoneResourceToTypeList =
                    zoneResourceTypeList
                            .stream().map(x -> new ZoneResourceToType(zoneResource.getId(), x.getId()))
                            .collect(Collectors.toList());
            // 建立资源和资源类别关联
            zoneResourceToTypeMapper.batchResourceToType(zoneResourceToTypeList);
        }
        return selectZoneResourceDataById(zoneResource.getId());
    }

    /**
     * 获取所有文件后缀（去重）
     *
     * @param fileIds
     */
    @Override
    public List<String> getAllFileSuffix(String fileIds) {
        List<SysFileInfo> sysFileInfoList = getAllFileByFileIds(fileIds);
        // 获取文件后缀列表
        List<String> suffixList = sysFileInfoList.stream()
                .map(x -> x.getFileSuffix().toLowerCase())
                .distinct()
                .collect(Collectors.toList());

        return suffixList;
    }

    public List<SysFileInfo> getAllFileByFileIds(String fileIds) {
        List<SysFileInfo> sysFileInfoList;
        try {
            sysFileInfoList = FeignUtils.getReturnData(
                    remoteFileService.getFileList(fileIds)
            );
        } catch (Exception e) {
            logger.error("从文件微服务获取资源附件时失败：{}", e.getMessage());
            throw new ServiceException("资源附件列表异常："+e.getMessage());
        }
        return sysFileInfoList;
    }

    @Override
    public int deleteMyZoneResourceByIds(Long[] ids) {
        for (Long id : ids) {
            ZoneResource zoneResource = selectZoneResourceById(id);
            if (!zoneResource.getCreateBy().equals(SecurityUtils.getUsername())) {
                throw new ServiceException("仅允许删除自身发布的资源");
            }
        }
        return zoneResourceMapper.deleteZoneResourceByIds(ids);
    }

    @Override
    public int auditZoneResource(ZoneResourceAuditVo zoneResourceAuditVo) {
        ZoneResource zoneResource = selectZoneResourceById(zoneResourceAuditVo.getId());
        if (!ZoneConstants.RESOURCE_AUDIT_PASS.equals(zoneResourceAuditVo.getAuditStatus())
                && !ZoneConstants.RESOURCE_AUDIT_FAILED.equals(zoneResourceAuditVo.getAuditStatus())) {
            throw new ServiceException("审核状态仅允许设置为审核通过和审核不通过");
        }
        if (!ZoneConstants.RESOURCE_NOT_AUDIT.equals(zoneResource.getAuditStatus())) {
            throw new ServiceException("该资源当前未处于待审核状态，不允许进行审核操作(资源名称[%s])", zoneResource.getName());
        }
        zoneResource.setAuditTime(DateUtils.getNowDate());
        zoneResource.setAuditBy(SecurityUtils.getUsername());
        zoneResource.setAuditStatus(zoneResourceAuditVo.getAuditStatus());
        zoneResource.setRemark(zoneResourceAuditVo.getRemark());
        return zoneResourceMapper.updateZoneResource(zoneResource);
    }

    @Override
    public ZoneResourceDataVo selectOpenZoneResourceDataById(Long resourceId, HttpServletRequest request) {
        ZoneResource zoneResource = selectZoneResourceById(resourceId);
        if (ZoneConstants.RESOURCE_AUDIT_PASS.equals(zoneResource.getAuditStatus())) {
            return zoneResourceToData(zoneResource);
        } else {
            String gitLinkToken = AuthUtil.getGitLinkRequestToken(request);
            if (StringUtils.isNotEmpty(gitLinkToken)) {
                String currentUsername = FeignUtils.getReturnData(
                        remoteUserService.getUserNameByGitLinkToken(gitLinkToken, SecurityConstants.INNER)
                );
                if (zoneResource.getCreateBy().equals(currentUsername)) {
                    return zoneResourceToData(zoneResource);
                }
            }
        }
        throw new ServiceException(HttpStatus.NOT_FOUND, "该资源无法访问");

    }

    @Override
    public GenericsTableDataInfo<ZoneResourceDataVo> selectMyZoneResourceList(ZoneResource zoneResourceSearch) {
        if (zoneResourceSearch == null || zoneResourceSearch.getZoneId() == null) {
            throw new ServiceException("获取我的资源列表时必须传入专区Id");
        }
        List<ZoneResource> zoneResourceList = zoneResourceMapper.selectZoneResourceList(zoneResourceSearch);
        return PageUtils.toPage(zoneResourceList, this::zoneResourceToData);
    }

    @Override
    public Integer selectMyZoneResourceCount(ZoneResource zoneResourceSearch) {
        return zoneResourceMapper.selectZoneResourceCount(zoneResourceSearch);
    }

    /**
     * 检查该特色专区下是否已存在该名称的资源
     *
     * @param zoneId
     * @param name
     */
    private void checkNameInZone(Long zoneId, String name) {
        ZoneResource oldZoneResource = zoneResourceMapper.selectZoneResourceByNameAndZoneId(name, zoneId);
        if (oldZoneResource != null) {
            throw new ServiceException("该特色专区下资源名称已存在(资源名称[" + name + "])");
        }
    }

    /**
     * 修改特色专区资源聚合
     *
     * @param zoneResourceUpdateVo 特色专区资源聚合
     * @return 结果
     */
    @Override
    public ZoneResourceDataVo updateZoneResource(ZoneResourceUpdateVo zoneResourceUpdateVo) {
        ZoneResource oldZoneResource = selectZoneResourceById(zoneResourceUpdateVo.getId());
        if (!oldZoneResource.getName().equals(zoneResourceUpdateVo.getName())) {
            checkNameInZone(oldZoneResource.getZoneId(), zoneResourceUpdateVo.getName());
        }
        if (zoneResourceUpdateVo.getFileIds() != null) {
            List<ZoneResourceToType> oldResourceToTypeList = zoneResourceToTypeMapper
                    .selectResourceToTypeListByResourceId(oldZoneResource.getId());
            List<Long> oldTypeIdList = oldResourceToTypeList.stream().map(ZoneResourceToType::getTypeId).collect(Collectors.toList());

            List<String> newFileSuffixList = getAllFileSuffix(zoneResourceUpdateVo.getFileIds());
            List<ZoneResourceType> newZoneResourceTypeList = zoneResourceTypeService
                    .selectZoneResourceTypeListBySuffixList(oldZoneResource.getZoneId(), newFileSuffixList);
            List<Long> newTypeIdList = newZoneResourceTypeList.stream().map(ZoneSort::getId).collect(Collectors.toList());

            // 获取新增的类型关联关系
            List<ZoneResourceToType> addZoneResourceToTypeList = newTypeIdList
                    .stream()
                    .filter(x -> !oldTypeIdList.contains(x))
                    .map(x -> new ZoneResourceToType(oldZoneResource.getId(), x))
                    .collect(Collectors.toList());
            // 建立资源与资源类型新的关联关系
            if (!addZoneResourceToTypeList.isEmpty()) {
                zoneResourceToTypeMapper.batchResourceToType(addZoneResourceToTypeList);
            }

            // 获取删除的类型Id列表
            Long[] delZoneResourceTypeIds = newTypeIdList
                    .stream()
                    .filter(x -> !newTypeIdList.contains(x))
                    .collect(Collectors.toList())
                    .toArray(new Long[0]);
            if (delZoneResourceTypeIds.length > 0) {
                // 删除资源与资源类型关联关系
                zoneResourceToTypeMapper.deleteResourceToTypesByResourceIdAndTypeIds(oldZoneResource.getId(), delZoneResourceTypeIds);
            }
        }
        //检查资源领域是否存在
        if (zoneResourceUpdateVo.getDomainId() != null
                && !zoneResourceUpdateVo.getDomainId().equals(oldZoneResource.getDomainId())) {
            zoneResourceDomainService.selectZoneResourceDomainById(zoneResourceUpdateVo.getDomainId());
        }

        ZoneResource zoneResource = zoneResourceUpdateVo.toZoneResource();
        zoneResource.setUpdateTime(DateUtils.getNowDate());
        zoneResource.setUpdateBy(SecurityUtils.getUsername());
        if (zoneResourceUpdateVo.getOrder() != null) {
            Integer setSort =
                    zoneSortService.setSortByDescOrder(oldZoneResource, zoneResourceUpdateVo.getOrder(), ZoneResource.table_name);
            zoneResource.setSort(setSort);
        }
        ZoneDetail zoneDetail = zoneDetailService.selectZoneDetailById(oldZoneResource.getZoneId());
        // 专区开启资源审核后，专区会员和专区运营人员编辑资源都需要审核
        if (resourceNeedAudit(zoneDetail)) {
            zoneResource.setAuditStatus(ZoneConstants.RESOURCE_NOT_AUDIT);
        }
        zoneResourceMapper.updateZoneResource(zoneResource);
        return selectZoneResourceDataById(oldZoneResource.getId());
    }

    /**
     * 批量删除特色专区资源聚合
     *
     * @param ids 需要删除的特色专区资源聚合主键
     * @return 结果
     */
    @Override
    public int deleteZoneResourceByIds(Long[] ids) {
        int success = 0;
        for (Long id : ids) {
            success += deleteZoneResourceById(id);
        }
        return success;
    }

    /**
     * 删除特色专区资源聚合信息
     *
     * @param id 特色专区资源聚合主键
     * @return 结果
     */
    @Override
    public int deleteZoneResourceById(Long id) {
        selectZoneResourceById(id);
        zoneSpecialProjectRelevancyService.deleteZoneSpecialProjectRelevancyByResourceId(id);
        return zoneResourceMapper.deleteZoneResourceById(id);
    }

    @Override
    @DataScope(deptAlias = "zr")
    public Integer selectZoneResourceCount(ZoneResource zoneResource) {
        return zoneResourceMapper.selectZoneResourceCount(zoneResource);
    }

    @Override
    public ZoneResourceDataVo selectZoneResourceDataById(Long id) {
        ZoneResource zoneResource = selectZoneResourceById(id);
        return zoneResourceToData(zoneResource);
    }
}
