package tech.easyflow.admin.controller.skill.vo;

import com.easyagents.skill.util.SkillResources;
import tech.easyflow.skill.entity.Skill;
import tech.easyflow.skill.entity.SkillResource;
import tech.easyflow.skill.entity.SkillToolBinding;

import java.math.BigInteger;
import java.util.Date;
import java.util.List;

/**
 * 管理端 Skill 安全视图。
 *
 * @param id Skill ID
 * @param categoryId 分类 ID
 * @param name 标准名称
 * @param displayName 展示名称
 * @param description 用途描述
 * @param visibilityScope 使用范围
 * @param packageHash 标准包哈希
 * @param snapshotHash 发布快照哈希
 * @param publishStatus 发布状态
 * @param currentApprovalInstanceId 当前审批实例 ID
 * @param approvalPending 是否审批中
 * @param currentApprovalActionType 当前审批动作
 * @param displayPublishStatus 展示状态
 * @param created 创建时间
 * @param modified 修改时间
 * @param createdByName 创建人昵称与账号
 * @param readable 是否可读
 * @param manageable 是否可管理
 * @param resources 资源摘要
 * @param toolBindings 平台 Tool 草稿绑定摘要
 * @param toolCount 实际 Tool 数
 * @param hasToolUpdate Tool 草稿是否与线上快照不同
 */
public record SkillView(BigInteger id,
                        BigInteger categoryId,
                        String name,
                        String displayName,
                        String description,
                        String visibilityScope,
                        String packageHash,
                        String snapshotHash,
                        String publishStatus,
                        BigInteger currentApprovalInstanceId,
                        Boolean approvalPending,
                        String currentApprovalActionType,
                        String displayPublishStatus,
                        Date created,
                        Date modified,
                        String createdByName,
                        boolean readable,
                        boolean manageable,
                        List<ResourceView> resources,
                        List<ToolBindingView> toolBindings,
                        int toolCount,
                        boolean hasToolUpdate) {

    /**
     * 从领域实体构造管理端视图。
     *
     * @param skill Skill 实体
     * @param readable 是否可读
     * @param manageable 是否可管理
     * @return 管理端视图
     */
    public static SkillView from(Skill skill, boolean readable, boolean manageable) {
        List<ResourceView> resources = skill.getResources() == null ? null
                : skill.getResources().stream().map(ResourceView::from).toList();
        List<ToolBindingView> toolBindings = skill.getToolBindings() == null ? null
                : skill.getToolBindings().stream().map(ToolBindingView::from).toList();
        int toolCount = skill.getToolBindings() == null ? 0 : skill.getToolBindings().stream()
                .mapToInt(binding -> "MCP".equalsIgnoreCase(binding.getToolType())
                        ? Math.max(0, binding.getMcpToolCount() == null ? 0 : binding.getMcpToolCount()) : 1)
                .sum();
        return new SkillView(skill.getId(), skill.getCategoryId(), skill.getName(), skill.getDisplayName(),
                skill.getDescription(), skill.getVisibilityScope(), skill.getPackageHash(),
                skill.getSnapshotHash(), skill.getPublishStatus(), skill.getCurrentApprovalInstanceId(),
                skill.getApprovalPending(), skill.getCurrentApprovalActionType(), skill.getDisplayPublishStatus(),
                skill.getCreated(), skill.getModified(), skill.getCreatedByName(), readable, manageable, resources,
                toolBindings, toolCount, hasToolUpdate(skill));
    }

    /**
     * Skill 包内资源摘要。
     *
     * @param id 资源 ID
     * @param path 标准相对路径
     * @param kind 按路径派生的语义类型
     * @param mediaType 媒体类型
     * @param isText 是否文本
     * @param contentHash 内容哈希
     * @param size 字节数
     */
    public record ResourceView(BigInteger id, String path, String kind, String mediaType,
                               Boolean isText, String contentHash, Long size) {

        /**
         * 转换资源实体。
         *
         * @param resource 资源实体
         * @return 资源摘要
         */
        public static ResourceView from(SkillResource resource) {
            String path = resource.getNormalizedPath();
            return new ResourceView(resource.getId(), path, SkillResources.classify(path).name(),
                    resource.getMediaType(), resource.getIsText(), resource.getContentHash(), resource.getSize());
        }
    }

    private static boolean hasToolUpdate(Skill skill) {
        if (skill.getToolBindings() == null) {
            return false;
        }
        Object published = skill.getPublishedToolBindingsJson() == null
                ? null : skill.getPublishedToolBindingsJson().get("bindings");
        List<String> currentKeys = skill.getToolBindings().stream().map(SkillView::bindingKey).toList();
        if (!(published instanceof List<?> list)) {
            return !currentKeys.isEmpty();
        }
        List<String> publishedKeys = list.stream().map(item -> {
            if (!(item instanceof java.util.Map<?, ?> map)) {
                return "INVALID";
            }
            return String.valueOf(map.get("toolType")) + ":" + map.get("targetId") + ":"
                    + Boolean.TRUE.equals(map.get("hitlEnabled")) + ":" + map.get("mcpToolManifestHash");
        }).toList();
        return !currentKeys.equals(publishedKeys);
    }

    private static String bindingKey(SkillToolBinding binding) {
        return binding.getToolType() + ":" + binding.getTargetId() + ":"
                + Boolean.TRUE.equals(binding.getHitlEnabled()) + ":" + binding.getMcpToolManifestHash();
    }

    /**
     * Skill 平台 Tool 草稿绑定安全摘要。
     */
    public record ToolBindingView(BigInteger id, String toolType, BigInteger targetId,
                                  Boolean hitlEnabled, Integer mcpToolCount,
                                  String mcpToolManifestHash, Integer sortNo,
                                  java.util.Map<String, Object> resourceSummary) {
        /** @param binding 绑定实体 @return 安全摘要 */
        public static ToolBindingView from(SkillToolBinding binding) {
            return new ToolBindingView(binding.getId(), binding.getToolType(), binding.getTargetId(),
                    binding.getHitlEnabled(), binding.getMcpToolCount(), binding.getMcpToolManifestHash(),
                    binding.getSortNo(), binding.getResourceSummary());
        }
    }
}
