package tech.easyflow.ai.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tech.easyflow.ai.entity.*;
import tech.easyflow.ai.enums.PluginType;
import tech.easyflow.ai.mapper.PluginCategoryMappingMapper;
import tech.easyflow.ai.mapper.PluginMapper;
import tech.easyflow.ai.plugin.workflow.availability.WorkflowPluginAvailabilityDecision;
import tech.easyflow.ai.plugin.workflow.availability.WorkflowPluginAvailabilityService;
import tech.easyflow.ai.plugin.workflow.binding.WorkflowPluginBindingService;
import tech.easyflow.ai.service.BotPluginService;
import tech.easyflow.ai.service.PluginItemService;
import tech.easyflow.ai.service.PluginService;
import tech.easyflow.ai.service.PluginVisibilityService;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
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.Date;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static tech.easyflow.ai.entity.table.PluginTableDef.PLUGIN;

/**
 * 服务层实现。
 *
 * @author WangGangqiang
 * @since 2025-04-25
 */
@Service
public class PluginServiceImpl extends ServiceImpl<PluginMapper, Plugin> implements PluginService {

    private static final Logger log = LoggerFactory.getLogger(PluginServiceImpl.class);

    @Resource
    PluginMapper pluginMapper;

    @Resource
    PluginCategoryMappingMapper pluginCategoryMappingMapper;

    @Resource
    private BotPluginService botPluginService;

    @Resource
    private PluginItemService pluginItemService;
    @Resource
    private CategoryPermissionService categoryPermissionService;
    @Resource
    private PluginVisibilityService pluginVisibilityService;
    @Resource
    private WorkflowPluginBindingService workflowPluginBindingService;
    @Resource
    private WorkflowPluginAvailabilityService workflowPluginAvailabilityService;

    @Override
    public Plugin savePlugin(Plugin plugin) {
        PluginType pluginType = PluginType.from(plugin.getType());
        if (pluginType == PluginType.WORKFLOW) {
            return workflowPluginBindingService.saveWorkflowPlugin(plugin);
        }
        normalizeHttpPlugin(plugin, true);
        plugin.setCreated(new Date());
        int insert = pluginMapper.insert(plugin);
        if (insert <= 0) {
            throw new BusinessException("保存失败");
        }
        return plugin;
    }

    @Override
    @Transactional
    public boolean removePlugin(String id) {

        List<PluginItem> pluginItems = pluginItemService.getByPluginId(id);
        List<BigInteger> pluginToolIds = new ArrayList<>();

        if (pluginItems != null && !pluginItems.isEmpty()) {

            pluginToolIds = pluginItems.stream().map(PluginItem::getId).collect(Collectors.toList());
            QueryWrapper queryWrapper = QueryWrapper.create();
            queryWrapper.in(BotPlugin::getPluginItemId, pluginToolIds);
            boolean exists = botPluginService.exists(queryWrapper);

            if (exists){
                throw new BusinessException("插件中有工具还关联着bot，请先取消关联！");
            }

        }

        if ( !pluginToolIds.isEmpty()) {
           boolean result =  pluginItemService.removeByIds(pluginToolIds);
           if (!result){
               log.error("删除插件工具表结果为0");
               throw new BusinessException("删除失败，请稍后重试！");
           }
        }


        int remove = pluginMapper.deleteById(id);
        if (remove <= 0) {
            log.error("删除插件结果为0");
            throw new BusinessException("删除失败，请稍后重试！");
        }

        return true;

    }

    @Override
    public List<Plugin> getList() {
        QueryWrapper queryWrapper = QueryWrapper.create().select();
        return pluginMapper.selectListByQueryAs(queryWrapper, Plugin.class);
    }

    @Override
    public Result<Page<Plugin>> pageByCategory(Long pageNumber, Long pageSize, int category) {
        RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("PLUGIN");
        QueryWrapper queryWrapper = QueryWrapper.create().select(PluginCategoryMapping::getPluginId)
                .eq(PluginCategoryMapping::getCategoryId, category);
        List<BigInteger> allCategoryPluginIds = pluginCategoryMappingMapper.selectListByQueryAs(queryWrapper, BigInteger.class)
                .stream()
                .filter(item -> item != null)
                .collect(Collectors.toCollection(ArrayList::new));
        if (CollectionUtil.isEmpty(allCategoryPluginIds)) {
            return Result.ok(new Page<>(Collections.emptyList(), pageNumber, pageSize, 0L));
        }

        List<BigInteger> orderedCategoryPluginIds = new ArrayList<>(new LinkedHashSet<>(allCategoryPluginIds));
        List<BigInteger> visiblePluginIds = orderedCategoryPluginIds;
        if (access.isRestricted()) {
            Set<BigInteger> visiblePluginIdSet = new LinkedHashSet<>(pluginVisibilityService.getCurrentVisiblePluginIds());
            List<BigInteger> creatorPluginIds = queryCreatorPluginIds(orderedCategoryPluginIds, access.getAccountIdAsLong());
            LinkedHashSet<BigInteger> mergedVisibleIds = orderedCategoryPluginIds.stream()
                    .filter(pluginId -> visiblePluginIdSet.contains(pluginId) || creatorPluginIds.contains(pluginId))
                    .collect(Collectors.toCollection(LinkedHashSet::new));
            visiblePluginIds = new ArrayList<>(mergedVisibleIds);
        }
        if (visiblePluginIds.isEmpty()) {
            return Result.ok(new Page<>(Collections.emptyList(), pageNumber, pageSize, 0L));
        }

        List<Plugin> totalPlugins = preparePluginsForCurrentUser(queryPluginsByIds(visiblePluginIds), true, false);
        int fromIndex = Math.max(0, Math.toIntExact((pageNumber - 1) * pageSize));
        if (fromIndex >= totalPlugins.size()) {
            return Result.ok(new Page<>(Collections.emptyList(), pageNumber, pageSize, totalPlugins.size()));
        }
        int toIndex = Math.min(totalPlugins.size(), Math.toIntExact(fromIndex + pageSize));
        Page<Plugin> aiPluginPage = new Page<>(new ArrayList<>(totalPlugins.subList(fromIndex, toIndex)),
                pageNumber, pageSize, totalPlugins.size());
        return Result.ok(aiPluginPage);
    }

    @Override
    public boolean updatePlugin(Plugin plugin) {
        Plugin existed = pluginMapper.selectOneById(plugin.getId());
        if (existed == null) {
            throw new BusinessException("插件不存在");
        }
        PluginType existedType = PluginType.from(existed.getType());
        PluginType targetType = PluginType.from(plugin.getType() == null ? existed.getType() : plugin.getType());
        if (existedType != targetType) {
            throw new BusinessException("暂不支持切换插件类型");
        }
        if (targetType == PluginType.WORKFLOW) {
            return workflowPluginBindingService.updateWorkflowPlugin(plugin);
        }
        normalizeHttpPlugin(plugin, false);
        pluginMapper.update(plugin);
        return true;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<Plugin> preparePluginsForCurrentUser(List<Plugin> plugins, boolean managementView, boolean availableOnly) {
        if (plugins == null || plugins.isEmpty()) {
            return Collections.emptyList();
        }
        List<Plugin> result = new ArrayList<>();
        for (Plugin plugin : plugins) {
            Plugin prepared = preparePluginForCurrentUser(plugin);
            if (!PluginType.isWorkflow(prepared.getType())) {
                result.add(prepared);
                continue;
            }
            boolean canKeepUnavailable = managementView && workflowPluginAvailabilityService.canViewUnavailableInManagement(prepared);
            if (Boolean.TRUE.equals(prepared.getAvailable())) {
                result.add(prepared);
                continue;
            }
            if (availableOnly) {
                continue;
            }
            if (canKeepUnavailable) {
                result.add(prepared);
            }
        }
        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Plugin preparePluginForCurrentUser(Plugin plugin) {
        if (plugin == null) {
            return null;
        }
        plugin.setType(PluginType.from(plugin.getType()).getCode());
        if (!PluginType.isWorkflow(plugin.getType())) {
            plugin.setAvailable(true);
            plugin.setReasonCode(null);
            plugin.setReasonMessage(null);
            return plugin;
        }
        WorkflowPluginAvailabilityDecision decision = workflowPluginAvailabilityService.evaluateForCurrentUser(plugin);
        plugin.setWorkflowTitle(decision.getWorkflowTitle());
        plugin.setAvailable(decision.isAvailable());
        plugin.setReasonCode(decision.getReasonCode());
        plugin.setReasonMessage(decision.getReasonMessage());
        return plugin;
    }

    private List<BigInteger> queryCreatorPluginIds(List<BigInteger> pluginIds, Long creatorId) {
        if (CollectionUtil.isEmpty(pluginIds) || creatorId == null) {
            return Collections.emptyList();
        }
        QueryWrapper creatorPluginWrapper = QueryWrapper.create().select(Plugin::getId)
                .in(Plugin::getId, pluginIds)
                .eq(Plugin::getCreatedBy, creatorId);
        return pluginMapper.selectListByQueryAs(creatorPluginWrapper, BigInteger.class);
    }

    private List<Plugin> queryPluginsByIds(List<BigInteger> pluginIds) {
        if (CollectionUtil.isEmpty(pluginIds)) {
            return Collections.emptyList();
        }
        QueryWrapper queryPluginWrapper = QueryWrapper.create().select().in(Plugin::getId, pluginIds);
        List<Plugin> plugins = pluginMapper.selectListWithRelationsByQuery(queryPluginWrapper);
        Map<BigInteger, Plugin> pluginMap = plugins.stream().collect(Collectors.toMap(
                Plugin::getId,
                item -> item,
                (left, right) -> left,
                LinkedHashMap::new
        ));
        List<Plugin> orderedPlugins = new ArrayList<>();
        for (BigInteger pluginId : pluginIds) {
            Plugin plugin = pluginMap.get(pluginId);
            if (plugin != null) {
                orderedPlugins.add(plugin);
            }
        }
        return orderedPlugins;
    }

    /**
     * 归一化 HTTP 插件基础字段。
     *
     * @param plugin 插件
     * @param isSave 是否为创建
     */
    private void normalizeHttpPlugin(Plugin plugin, boolean isSave) {
        plugin.setType(PluginType.HTTP.getCode());
        plugin.setWorkflowId(null);
        LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
        if (isSave && loginAccount != null && loginAccount.getId() != null) {
            plugin.setCreatedBy(loginAccount.getId().longValue());
            plugin.setDeptId(loginAccount.getDeptId() == null ? null : loginAccount.getDeptId().longValue());
            plugin.setTenantId(loginAccount.getTenantId() == null ? null : loginAccount.getTenantId().longValue());
        }
        if (plugin.getHeaders() != null && !(plugin.getHeaders() instanceof String)) {
            plugin.setHeaders(plugin.getHeaders().toString());
        }
    }

}
