package tech.easyflow.ai.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tech.easyflow.ai.entity.Plugin;
import tech.easyflow.ai.entity.PluginCategory;
import tech.easyflow.ai.entity.PluginCategoryMapping;
import tech.easyflow.ai.mapper.PluginCategoryMapper;
import tech.easyflow.ai.mapper.PluginCategoryMappingMapper;
import tech.easyflow.ai.mapper.PluginMapper;
import tech.easyflow.ai.service.PluginCategoryMappingService;
import tech.easyflow.ai.service.PluginVisibilityService;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
import tech.easyflow.system.service.CategoryPermissionService;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 *  服务层实现。
 *
 * @author Administrator
 * @since 2025-05-21
 */
@Service
public class PluginCategoryMappingServiceImpl extends ServiceImpl<PluginCategoryMappingMapper, PluginCategoryMapping>  implements PluginCategoryMappingService {

    @Resource
    private PluginCategoryMappingMapper relationMapper;

    @Resource
    private PluginCategoryMapper pluginCategoryMapper;
    @Resource
    private PluginMapper pluginMapper;
    @Resource
    private PluginVisibilityService pluginVisibilityService;
    @Resource
    private CategoryPermissionService categoryPermissionService;

    @Override
    @Transactional
    public boolean updateRelation(BigInteger pluginId, List<BigInteger> categoryIds) {
        if (pluginId == null) {
            throw new BusinessException("插件ID不能为空");
        }
        Plugin plugin = pluginMapper.selectOneById(pluginId);
        if (plugin == null) {
            throw new BusinessException("插件不存在");
        }
        pluginVisibilityService.assertPluginVisible(plugin.getCreatedBy(), pluginId, "无权限访问插件");

        List<BigInteger> targetCategoryIds = categoryIds == null
                ? Collections.emptyList()
                : categoryIds.stream()
                .filter(java.util.Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        assertCategoryIdsValid(targetCategoryIds);
        assertCategoryAccess(targetCategoryIds);

        QueryWrapper currentRelationQuery = QueryWrapper.create().select("category_id")
                .from("tb_plugin_category_mapping")
                .where("plugin_id = ?", pluginId);
        List<BigInteger> currentCategoryIds = relationMapper.selectListByQueryAs(currentRelationQuery, BigInteger.class);
        Set<BigInteger> currentCategoryIdSet = new LinkedHashSet<>(currentCategoryIds);
        Set<BigInteger> targetCategoryIdSet = new LinkedHashSet<>(targetCategoryIds);

        Set<BigInteger> categoryIdsToDelete = new LinkedHashSet<>(currentCategoryIdSet);
        categoryIdsToDelete.removeAll(targetCategoryIdSet);
        if (!categoryIdsToDelete.isEmpty()) {
            QueryWrapper deleteQuery = QueryWrapper.create()
                    .from("tb_plugin_category_mapping")
                    .where("plugin_id = ?", pluginId)
                    .in("category_id", new ArrayList<>(categoryIdsToDelete));
            relationMapper.deleteByQuery(deleteQuery);
        }

        Set<BigInteger> categoryIdsToInsert = new LinkedHashSet<>(targetCategoryIdSet);
        categoryIdsToInsert.removeAll(currentCategoryIdSet);
        for (BigInteger categoryId : categoryIdsToInsert) {
            PluginCategoryMapping pluginCategoryMapping = new PluginCategoryMapping();
            pluginCategoryMapping.setCategoryId(categoryId);
            pluginCategoryMapping.setPluginId(pluginId);
            int insert = relationMapper.insert(pluginCategoryMapping);
            if (insert <= 0) {
                throw new BusinessException("新增分类关联失败");
            }
        }
        return true;
    }

    private void assertCategoryIdsValid(List<BigInteger> targetCategoryIds) {
        if (CollectionUtil.isEmpty(targetCategoryIds)) {
            return;
        }
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(PluginCategory::getId)
                .in(PluginCategory::getId, targetCategoryIds);
        List<BigInteger> existedCategoryIds = pluginCategoryMapper.selectListByQueryAs(queryWrapper, BigInteger.class);
        if (existedCategoryIds == null || existedCategoryIds.size() != new LinkedHashSet<>(targetCategoryIds).size()) {
            throw new BusinessException("存在无效的插件分类");
        }
    }

    private void assertCategoryAccess(List<BigInteger> targetCategoryIds) {
        if (CollectionUtil.isEmpty(targetCategoryIds)) {
            return;
        }
        RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("PLUGIN");
        if (!access.isRestricted()) {
            return;
        }
        Set<BigInteger> allowedCategoryIds = access.getCategoryIds();
        if (CollectionUtil.isEmpty(allowedCategoryIds)) {
            throw new BusinessException("无权限关联所选插件分类");
        }
        boolean allAllowed = targetCategoryIds.stream().allMatch(allowedCategoryIds::contains);
        if (!allAllowed) {
            throw new BusinessException("无权限关联所选插件分类");
        }
    }

    @Override
    public List<PluginCategory>  getPluginCategories(BigInteger pluginId) {
        QueryWrapper categoryQueryWrapper =   QueryWrapper.create().select("category_id")
                .from("tb_plugin_category_mapping")
                .where("plugin_id  = ?", pluginId);
        List<BigInteger> categoryIdList =  relationMapper.selectListByQueryAs(categoryQueryWrapper, BigInteger.class);
        List<PluginCategory> pluginCategories = new ArrayList<PluginCategory>();
        if (categoryIdList.isEmpty()){
            return pluginCategories;
        }
        QueryWrapper categoryQuery =  QueryWrapper.create().select("id, name")
                .from("tb_plugin_category")
                .in("id", categoryIdList);
        pluginCategories = pluginCategoryMapper.selectListByQuery(categoryQuery);
        return pluginCategories;
    }
}
