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

import com.alibaba.fastjson2.JSONObject;
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.*;
import com.microservices.zone.resource.domain.vo.*;
import com.microservices.zone.resource.enums.AiResourceCategory;
import com.microservices.zone.resource.mapper.ZoneResourceMapper;
import com.microservices.zone.resource.mapper.ZoneResourceToTypeMapper;
import com.microservices.zone.resource.mapper.ZoneResourcesLikeMapper;
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.resource.service.IAiResourceParseService;
import com.microservices.zone.resource.utils.ResourceExtendDataUtils;
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 org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
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;
    @Autowired
    private ZoneResourcesLikeMapper zoneResourcesLikeMapper;
    @Autowired
    private IAiResourceParseService aiResourceParseService;

    /**
     * 查询特色专区资源聚合
     *
     * @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, z -> zoneResourceToData(z, true));
    }

    @Override
    @DataScope(deptAlias = "zr")
    public GenericsTableDataInfo<ZoneResourceDataVo> selectZoneResourceList(ZoneResourceOpenSearchVo zoneResourceSearchVo) {
        List<ZoneResource> zoneResourceList = zoneResourceMapper.selectZoneResourceListBySearchVo(zoneResourceSearchVo);
        return PageUtils.toPage(zoneResourceList, z -> zoneResourceToData(z, true));
    }

    private ZoneResourceDataVo zoneResourceToData(ZoneResource zoneResource, boolean removeSkill) {
        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);
        if (removeSkill && zoneResourceDataVo.getExtendData() != null) {
            zoneResourceDataVo.getExtendData().remove(ResourceExtendDataUtils.SKILL_ROOT);
        }
        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());
            return isOperator || isMember;
        }
        return false;
    }

    /**
     * 新增特色专区资源聚合
     *
     * @param zoneResourceInputVo 特色专区资源聚合
     * @return 结果
     */
    @Override
    public ZoneResourceDataVo insertZoneResource(ZoneResourceInputVo zoneResourceInputVo) {
        ZoneDetail zoneDetail = zoneDetailService.selectZoneDetailById(zoneResourceInputVo.getZoneId());
        checkNameInZone(zoneResourceInputVo.getZoneId(), zoneResourceInputVo.getName(), zoneResourceInputVo.getResourceCategory());
        zoneResourceDomainService.selectZoneResourceDomainById(zoneResourceInputVo.getDomainId());
        ZoneResource zoneResource = zoneResourceInputVo.toZoneResource();
        // 专区开启资源审核后，专区会员和专区运营人员新增资源都需要审核
        if (resourceNeedAudit(zoneDetail)) {
            zoneResource.setAuditStatus(ZoneConstants.RESOURCE_NOT_AUDIT);
        }
        zoneResource.setCreateTime(DateUtils.getNowDate());
        zoneResource.setUpdateTime(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);
        // 获取文件后缀列表

        return sysFileInfoList.stream()
                .map(x -> x.getFileSuffix().toLowerCase())
                .distinct()
                .collect(Collectors.toList());
    }

    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 (AiResourceCategory.isAiResourceCategory(zoneResource.getResourceCategory())) {
            // 增加浏览次数
            incrementViewCount(zoneResource.getId());
        }
        if (ZoneConstants.RESOURCE_AUDIT_PASS.equals(zoneResource.getAuditStatus())) {
            return zoneResourceToData(zoneResource, false);
        } 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, false);
                }
            }
        }
        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, x -> zoneResourceToData(x, true));
    }

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

    /**
     * 检查该特色专区下是否已存在该名称的资源
     *
     * @param zoneId
     * @param name
     */
    private void checkNameInZone(Long zoneId, String name, String resourceCategory) {
        ZoneResource oldZoneResource = zoneResourceMapper.selectZoneResourceByNameAndZoneId(name, zoneId, resourceCategory);
        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(), oldZoneResource.getResourceCategory());
        }
        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)).toArray(Long[]::new);
            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 (ZoneConstants.RESOURCE_DRAFT.equals(oldZoneResource.getAuditStatus())) {
            zoneResource.setAuditStatus(ZoneConstants.RESOURCE_NOT_AUDIT);
        } else 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, false);
    }

    // ==================== AI资源广场 Skill 功能 ====================

    @Override
    public ZoneResourceDataVo insertAiSkillResource(AiSkillInputVo inputVo) {
        ZoneResourceDomain zoneResourceDomain = zoneResourceDomainService.selectZoneResourceDomainById(inputVo.getDomainId());
        if (!AiResourceCategory.SKILL.getCode().equals(zoneResourceDomain.getDomainCategory())) {
            throw new ServiceException("当前资源领域非SKILL类型");
        }
        ZoneResourceInputVo zoneResourceInputVo = inputVo.toZoneResourceInputVo();
        return insertZoneResource(zoneResourceInputVo);
    }

    @Override
    public ZoneResourceDataVo updateAiSkillResource(AiSkillUpdateVo updateVo) {
        ZoneResource oldResource = getAiResourceById(updateVo.getId());
        if (!AiResourceCategory.SKILL.getCode().equals(oldResource.getResourceCategory())) {
            throw new ServiceException("当前资源非Skill资源");
        }
        // 已发布状态不允许直接修改
        if (ZoneConstants.RESOURCE_AUDIT_PASS.equals(oldResource.getAuditStatus())) {
            throw new ServiceException("已发布的资源不允许直接修改，请先下架后再修改");
        }
        if (ZoneConstants.RESOURCE_TAKEN_DOWN.equals(oldResource.getAuditStatus())) {
            oldResource.setAuditStatus(ZoneConstants.RESOURCE_NOT_AUDIT);
        }
        if (updateVo.getDomainId() != null) {
            ZoneResourceDomain zoneResourceDomain = zoneResourceDomainService.selectZoneResourceDomainById(updateVo.getDomainId());
            if (!AiResourceCategory.SKILL.getCode().equals(zoneResourceDomain.getDomainCategory())) {
                throw new ServiceException("当前资源领域非SKILL类型");
            }
        }
        ZoneResourceUpdateVo zoneResourceUpdateVo = updateVo.toZoneResourceUpdateVo(oldResource);
        return updateZoneResource(zoneResourceUpdateVo);
    }

    @Override
    public ZoneResourceDataVo selectAiSkillResourceById(Long id) {
        ZoneResource resource = getAiResourceById(id);
        return zoneResourceToData(resource, false);
    }

    @Override
    public GenericsTableDataInfo<ZoneResourceDataVo> selectAiSkillResourceList(ZoneResource zoneResource) {
        zoneResource.setResourceCategory(AiResourceCategory.SKILL.getCode());
        List<ZoneResource> list = zoneResourceMapper.selectZoneResourceList(zoneResource);
        return PageUtils.toPage(list, x -> zoneResourceToData(x, true));
    }

    @Override
    public GenericsTableDataInfo<ZoneResourceDataVo> selectAiModelResourceList(ZoneResource zoneResource) {
        zoneResource.setResourceCategory(AiResourceCategory.MODEL.getCode());
        List<ZoneResource> list = zoneResourceMapper.selectZoneResourceList(zoneResource);
        return PageUtils.toPage(list, x -> zoneResourceToData(x, true));
    }

    @Override
    public GenericsTableDataInfo<ZoneResourceDataVo> selectAiDatasetResourceList(ZoneResource zoneResource) {
        zoneResource.setResourceCategory(AiResourceCategory.DATASET.getCode());
        List<ZoneResource> list = zoneResourceMapper.selectZoneResourceList(zoneResource);
        return PageUtils.toPage(list, x -> zoneResourceToData(x, true));
    }

    @Override
    public UserResourceStatisticsVo getResourceStatistics(Long zoneId, Boolean isMine, String resourceCategory) {
        String createBy = null;
        if (isMine) {
            createBy = SecurityUtils.getUsername();
        }
        UserResourceStatisticsVo statistics = new UserResourceStatisticsVo();

        // 构造查询条件
        ZoneResource likeQuery = new ZoneResource();
        likeQuery.setZoneId(zoneId);
        if (StringUtils.isNotEmpty(createBy)) {
            likeQuery.setCreateBy(createBy);
        }
        if (StringUtils.isNotEmpty(resourceCategory)) {
            likeQuery.setResourceCategory(resourceCategory);
        }

        // 查询点赞总数
        List<ZoneResource> resourceList = zoneResourceMapper.selectZoneResourceList(likeQuery);
        int totalLikeCount = 0;
        for (ZoneResource resource : resourceList) {
            if (resource.getLikeCount() != null) {
                totalLikeCount += resource.getLikeCount();
            }
        }
        statistics.setLikeCount(totalLikeCount);

        // 统计已发布数量
        ZoneResource publishedQuery = new ZoneResource();
        publishedQuery.setZoneId(zoneId);
        if (StringUtils.isNotEmpty(createBy)) {
            publishedQuery.setCreateBy(createBy);
        }
        if (StringUtils.isNotEmpty(resourceCategory)) {
            publishedQuery.setResourceCategory(resourceCategory);
        }
        publishedQuery.setAuditStatus(ZoneConstants.RESOURCE_AUDIT_PASS);
        Integer publishedCount = zoneResourceMapper.selectZoneResourceCount(publishedQuery);
        statistics.setPublishedCount(publishedCount);

        // 统计待审核数量
        ZoneResource pendingQuery = new ZoneResource();
        pendingQuery.setZoneId(zoneId);
        if (StringUtils.isNotEmpty(createBy)) {
            pendingQuery.setCreateBy(createBy);
        }
        if (StringUtils.isNotEmpty(resourceCategory)) {
            pendingQuery.setResourceCategory(resourceCategory);
        }
        pendingQuery.setAuditStatus(ZoneConstants.RESOURCE_NOT_AUDIT);
        Integer pendingCount = zoneResourceMapper.selectZoneResourceCount(pendingQuery);
        statistics.setPendingCount(pendingCount);

        return statistics;
    }

    @Override
    public int takeDownAiResource(Long id, String reason) {
        ZoneResource resource = getAiResourceById(id);

        if (!ZoneConstants.RESOURCE_AUDIT_PASS.equals(resource.getAuditStatus())) {
            throw new ServiceException("仅已发布的资源可以下架");
        }

        resource.setAuditStatus(ZoneConstants.RESOURCE_TAKEN_DOWN);
        if (StringUtils.isNotEmpty(reason)) {
            resource.setRemark(reason);
        }
        resource.setUpdateTime(DateUtils.getNowDate());
        resource.setUpdateBy(SecurityUtils.getUsername());
        return zoneResourceMapper.updateZoneResource(resource);
    }

    @Override
    public int takeUpAiResource(Long id, String reason) {
        ZoneResource resource = getAiResourceById(id);
        if (!ZoneConstants.RESOURCE_TAKEN_DOWN.equals(resource.getAuditStatus())) {
            throw new ServiceException("仅已下架的资源可以重新上架");
        }

        resource.setAuditStatus(ZoneConstants.RESOURCE_AUDIT_PASS);
        if (StringUtils.isNotEmpty(reason)) {
            resource.setRemark(reason);
        }
        resource.setUpdateTime(DateUtils.getNowDate());
        resource.setUpdateBy(SecurityUtils.getUsername());
        return zoneResourceMapper.updateZoneResource(resource);
    }

    @Override
    public List<JSONObject> selectZoneResourcesIsLike(String ids) {
        List<JSONObject> list = new ArrayList<>();
        if (StringUtils.isNotEmpty(ids)) {
            String[] idArr = ids.split(",");
            List<ZoneResourcesLike> zoneResourcesLikeList = zoneResourcesLikeMapper.selectByResourceIds(idArr);
            for (int i = 0; i < idArr.length; i++) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("id", idArr[i]);
                if (zoneResourcesLikeList != null && !zoneResourcesLikeList.isEmpty()) {
                    int finalI = i;
                    jsonObject.put("isLike", zoneResourcesLikeList.stream().anyMatch(x -> idArr[finalI].equals(String.valueOf(x.getResourceId()))));
                } else {
                    jsonObject.put("isLike", false);
                }
                list.add(jsonObject);
            }
        }
        return list;
    }

    @Override
    public int resubmitAiResource(Long id) {
        ZoneResource resource = getAiResourceById(id);
        checkResourceOwner(resource);

        if (!ZoneConstants.RESOURCE_AUDIT_FAILED.equals(resource.getAuditStatus())
                && !ZoneConstants.RESOURCE_TAKEN_DOWN.equals(resource.getAuditStatus())
                && !ZoneConstants.RESOURCE_DRAFT.equals(resource.getAuditStatus())) {
            throw new ServiceException("仅被驳回、已下架或草稿的资源可以重新提交");
        }

        resource.setAuditStatus(ZoneConstants.RESOURCE_NOT_AUDIT);
        resource.setRemark(null);
        resource.setUpdateTime(DateUtils.getNowDate());
        return zoneResourceMapper.updateZoneResource(resource);
    }

    @Override
    public int withdrawAiResource(Long id) {
        ZoneResource resource = getAiResourceById(id);
        checkResourceOwner(resource);

        if (!ZoneConstants.RESOURCE_NOT_AUDIT.equals(resource.getAuditStatus())) {
            throw new ServiceException("仅待审核的资源可以撤回");
        }

        resource.setAuditStatus(ZoneConstants.RESOURCE_DRAFT);
        resource.setUpdateTime(DateUtils.getNowDate());
        return zoneResourceMapper.updateZoneResource(resource);
    }

    @Override
    public List<ZoneResourceDataVo> selectSkillRecommendations(int limit) {
        List<ZoneResource> list = zoneResourceMapper.selectSkillRecommendations(
                AiResourceCategory.SKILL.getCode(), ZoneConstants.RESOURCE_AUDIT_PASS, limit);
        return list.stream().map(z -> zoneResourceToData(z, false)).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean toggleZoneResourcesLike(Long resourceId) {
        // 校验资源存在且已发布
        ZoneResource resource = getAiResourceById(resourceId);
        if (!ZoneConstants.RESOURCE_AUDIT_PASS.equals(resource.getAuditStatus())) {
            throw new ServiceException("仅已发布的资源可以点赞");
        }

        Long userId = SecurityUtils.getGitlinkUserId();
        if (userId == null) {
            throw new ServiceException("当前用户未绑定平台账号，无法点赞");
        }

        ZoneResourcesLike existingLike = zoneResourcesLikeMapper.selectByResourceAndUser(resourceId, userId);
        if (existingLike != null) {
            // 取消点赞
            zoneResourcesLikeMapper.deleteLike(resourceId, userId);
            zoneResourceMapper.updateLikeCount(resourceId, -1);
            return false;
        } else {
            // 新增点赞
            ZoneResourcesLike like = new ZoneResourcesLike();
            like.setResourceId(resourceId);
            like.setUserId(userId);
            like.setCreateTime(DateUtils.getNowDate());
            zoneResourcesLikeMapper.insertLike(like);
            zoneResourceMapper.updateLikeCount(resourceId, 1);
            return true;
        }
    }

    @Override
    public void incrementViewCount(Long id) {
        zoneResourceMapper.incrementViewCount(id);
    }

    // ==================== AI资源辅助方法 ====================

    private ZoneResource getAiResourceById(Long id) {
        ZoneResource resource = zoneResourceMapper.selectZoneResourceById(id);
        if (resource == null) {
            throw new ServiceException("资源不存在(资源id[" + id + "])");
        }
        if (!AiResourceCategory.isAiResourceCategory(resource.getResourceCategory())) {
            throw new ServiceException("该资源不是AI资源");
        }
        return resource;
    }

    private void checkResourceOwner(ZoneResource resource) {
        if (!resource.getCreateBy().equals(SecurityUtils.getUsername())) {
            throw new ServiceException("仅允许操作自己发布的资源");
        }
    }

    private void validateSkillNameUnique(String name, Long excludeId) {
        if (StringUtils.isEmpty(name)) {
            return;
        }
        ZoneResource existing = zoneResourceMapper.selectSkillResourceByName(name);
        if (existing != null && !existing.getId().equals(excludeId)) {
            throw new ServiceException("Skill名称已存在(名称[" + name + "])");
        }
    }

    private void validateKeywords(String keywords) {
        if (StringUtils.isEmpty(keywords)) {
            return;
        }
        String[] tags = keywords.split(",");
        if (tags.length > ZoneConstants.KEYWORD_MAX_COUNT) {
            throw new ServiceException("标签数量不能超过" + ZoneConstants.KEYWORD_MAX_COUNT + "个");
        }
        for (String tag : tags) {
            if (tag.trim().length() > ZoneConstants.KEYWORD_MAX_LENGTH) {
                throw new ServiceException("单个标签不能超过" + ZoneConstants.KEYWORD_MAX_LENGTH + "个字符");
            }
        }
    }

    // ==================== AI资源广场 Model 功能 ====================

    @Override
    public ZoneResourceDataVo insertAiModelResource(AiModelInputVo inputVo) {
        // 1. 校验领域类型是否为 MODEL
        ZoneResourceDomain zoneResourceDomain = zoneResourceDomainService.selectZoneResourceDomainById(inputVo.getDomainId());
        if (zoneResourceDomain == null) {
            throw new ServiceException("资源领域不存在");
        }
        if (!AiResourceCategory.MODEL.getCode().equals(zoneResourceDomain.getDomainCategory())) {
            throw new ServiceException("当前资源领域非MODEL类型");
        }
        return insertModelOrDatasetResource(inputVo.toZoneResourceInputVo(), inputVo.getFileId());
    }

    @Override
    public ZoneResourceDataVo updateAiModelResource(AiModelUpdateVo updateVo) {
        // 1. 获取现有资源
        ZoneResource oldResource = getAiResourceById(updateVo.getId());
        if (!AiResourceCategory.MODEL.getCode().equals(oldResource.getResourceCategory())) {
            throw new ServiceException("当前资源非Model资源");
        }

        // 2. 状态校验
        if (ZoneConstants.RESOURCE_AUDIT_PASS.equals(oldResource.getAuditStatus())) {
            throw new ServiceException("已发布的资源不允许直接修改，请先下架后再修改");
        }
        if (ZoneConstants.RESOURCE_TAKEN_DOWN.equals(oldResource.getAuditStatus())) {
            oldResource.setAuditStatus(ZoneConstants.RESOURCE_NOT_AUDIT);
        }

        // 3. 领域校验
        if (updateVo.getDomainId() != null) {
            ZoneResourceDomain zoneResourceDomain = zoneResourceDomainService.selectZoneResourceDomainById(updateVo.getDomainId());
            if (zoneResourceDomain == null) {
                throw new ServiceException("资源领域不存在");
            }
            if (!AiResourceCategory.MODEL.getCode().equals(zoneResourceDomain.getDomainCategory())) {
                throw new ServiceException("当前资源领域非MODEL类型");
            }
        }

        return updateModelOrDatasetResource(oldResource, updateVo.toZoneResourceUpdateVo(oldResource), updateVo.getFileId());


    }

    private ZoneResourceDataVo updateModelOrDatasetResource(ZoneResource oldResource, ZoneResourceUpdateVo updateVo, Long fileId) {
        // 4. 获取 VO 层已合并的 extendData（可能包含 readmeContent），或使用旧的
        JSONObject extendData;
        if (updateVo.getExtendData() != null) {
            extendData = JSONObject.parseObject(updateVo.getExtendData());
        } else {
            extendData = oldResource.getExtendData();
        }
        if (extendData == null) {
            extendData = new JSONObject();
        }

        // 5. 如果更新了文件，重新解析
        if (fileId != null) {
            AiUploadedResourceParseResultVo parseResult = aiResourceParseService.parseUploadedZip(fileId);

            // 更新 extendData
            JSONObject fileTreeJsonObj = parseResult.getFileTreeJson();
            extendData = ResourceExtendDataUtils.updateModelOrDatasetReadmeContent(oldResource.getResourceCategory(), extendData, parseResult.getReadmeContent());
            extendData = ResourceExtendDataUtils.updateModelOrDatasetFileTree(oldResource.getResourceCategory(), extendData, fileTreeJsonObj);

            // 更新 fileSize
            if (!extendData.containsKey(oldResource.getResourceCategory())) {
                extendData.put(oldResource.getResourceCategory(), new JSONObject());
            }
            extendData.getJSONObject(oldResource.getResourceCategory()).put(ResourceExtendDataUtils.FILE_SIZE, parseResult.getFileSizeInfo());
        }


        if (fileId == null) {
            updateVo.setFileIds(oldResource.getFileIds());
        } else {
            updateVo.setFileIds(String.valueOf(fileId));
        }
        updateVo.setExtendData(extendData.toJSONString());

        // 7. 更新资源
        return updateZoneResource(updateVo);
    }

    @Override
    public ZoneResourceDataVo selectAiModelResourceById(Long id) {
        ZoneResource resource = getAiResourceById(id);
        if (!AiResourceCategory.MODEL.getCode().equals(resource.getResourceCategory())) {
            throw new ServiceException("当前资源非Model资源");
        }
        return zoneResourceToData(resource, false);
    }

    // ==================== AI资源广场 Dataset 功能 ====================

    @Override
    public ZoneResourceDataVo insertAiDatasetResource(AiDatasetInputVo inputVo) {
        // 1. 校验领域类型是否为 DATASET
        ZoneResourceDomain zoneResourceDomain = zoneResourceDomainService.selectZoneResourceDomainById(inputVo.getDomainId());
        if (zoneResourceDomain == null) {
            throw new ServiceException("资源领域不存在");
        }
        if (!AiResourceCategory.DATASET.getCode().equals(zoneResourceDomain.getDomainCategory())) {
            throw new ServiceException("当前资源领域非DATASET类型");
        }
        return insertModelOrDatasetResource(inputVo.toZoneResourceInputVo(), inputVo.getFileId());

    }

    private ZoneResourceDataVo insertModelOrDatasetResource(ZoneResourceInputVo inputVo, Long fileId) {
        // 2. 调用 parseUploadedZip 解析文件，获取 readmeContent 和 fileTreeJson
        AiUploadedResourceParseResultVo parseResult = aiResourceParseService.parseUploadedZip(fileId);

        JSONObject extendData = ResourceExtendDataUtils.buildModelOrDataSetExtendData(
                inputVo.getResourceCategory(), parseResult);
        inputVo.setExtendData(extendData.toJSONString());

        // 6. 创建资源
        return insertZoneResource(inputVo);
    }

    @Override
    public ZoneResourceDataVo updateAiDatasetResource(AiDatasetUpdateVo updateVo) {
        // 1. 获取现有资源
        ZoneResource oldResource = getAiResourceById(updateVo.getId());
        if (!AiResourceCategory.DATASET.getCode().equals(oldResource.getResourceCategory())) {
            throw new ServiceException("当前资源非Dataset资源");
        }

        // 2. 状态校验
        if (ZoneConstants.RESOURCE_AUDIT_PASS.equals(oldResource.getAuditStatus())) {
            throw new ServiceException("已发布的资源不允许直接修改，请先下架后再修改");
        }
        if (ZoneConstants.RESOURCE_TAKEN_DOWN.equals(oldResource.getAuditStatus())) {
            oldResource.setAuditStatus(ZoneConstants.RESOURCE_NOT_AUDIT);
        }

        // 3. 领域校验
        if (updateVo.getDomainId() != null) {
            ZoneResourceDomain zoneResourceDomain = zoneResourceDomainService.selectZoneResourceDomainById(updateVo.getDomainId());
            if (zoneResourceDomain == null) {
                throw new ServiceException("资源领域不存在");
            }
            if (!AiResourceCategory.DATASET.getCode().equals(zoneResourceDomain.getDomainCategory())) {
                throw new ServiceException("当前资源领域非DATASET类型");
            }
        }

        return updateModelOrDatasetResource(oldResource, updateVo.toZoneResourceUpdateVo(oldResource), updateVo.getFileId());
    }

    @Override
    public ZoneResourceDataVo selectAiDatasetResourceById(Long id) {
        ZoneResource resource = getAiResourceById(id);
        if (!AiResourceCategory.DATASET.getCode().equals(resource.getResourceCategory())) {
            throw new ServiceException("当前资源非Dataset资源");
        }
        return zoneResourceToData(resource, false);
    }

}
