package tech.easyflow.ai.easyagentsflow.repository;

import com.easyagents.flow.core.chain.ChainDefinition;
import org.springframework.stereotype.Component;
import tech.easyflow.ai.entity.Workflow;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 当前进程内的已发布 Agent 工作流冻结定义注册表。
 *
 * <p>正式 Agent 编译时使用发布快照中的工作流内容生成内容寻址定义，执行阶段只读取该定义，
 * 不再按工作流 ID 回查当前发布版本。注册表按访问顺序有界保留，Agent 再次编译时可无损重建。</p>
 */
@Component
public class FrozenWorkflowDefinitionRegistry {

    private static final String PREFIX = "agent-frozen:";
    private static final int MAX_ENTRIES = 512;

    private final AgentWorkflowSnapshotFactory snapshotFactory;
    private final Map<String, ChainDefinition> definitions =
            new LinkedHashMap<>(32, 0.75F, true);
    private final Map<String, Workflow> workflows =
            new LinkedHashMap<>(32, 0.75F, true);

    /**
     * 创建冻结定义注册表。
     *
     * @param snapshotFactory Agent Workflow 冻结快照工厂
     */
    public FrozenWorkflowDefinitionRegistry(AgentWorkflowSnapshotFactory snapshotFactory) {
        this.snapshotFactory = snapshotFactory;
    }

    /**
     * 注册一份工作流快照并返回内容寻址定义 ID。
     *
     * @param workflow 包含完整 content 的工作流快照
     * @return 冻结定义 ID
     * @throws tech.easyflow.common.web.exceptions.BusinessException 工作流快照不完整或不兼容时抛出
     */
    public String register(Workflow workflow) {
        AgentWorkflowSnapshotFactory.PreparedWorkflow prepared = snapshotFactory.prepare(workflow);
        String preparedContent = prepared.content();
        String id = PREFIX + workflow.getId() + ":" + sha256(preparedContent);
        synchronized (definitions) {
            if (definitions.containsKey(id)) {
                definitions.get(id);
                return id;
            }
            ChainDefinition definition = prepared.definition();
            definition.setId(id);
            definition.setName(workflow.getEnglishName());
            definition.setDescription(workflow.getDescription());
            definitions.put(id, definition);
            workflows.put(id, workflow);
            while (definitions.size() > MAX_ENTRIES) {
                String eldest = definitions.keySet().iterator().next();
                definitions.remove(eldest);
                workflows.remove(eldest);
            }
        }
        return id;
    }

    /**
     * 获取已注册冻结定义。
     *
     * @param definitionId 定义 ID
     * @return 冻结定义；不存在时返回 null
     */
    public ChainDefinition get(String definitionId) {
        synchronized (definitions) {
            return definitions.get(definitionId);
        }
    }

    /**
     * 获取冻结定义对应的工作流快照，用于执行审计展示。
     *
     * @param definitionId 冻结定义 ID
     * @return 工作流快照；不存在时返回 null
     */
    public Workflow getWorkflow(String definitionId) {
        synchronized (definitions) {
            return workflows.get(definitionId);
        }
    }

    /**
     * 判断定义 ID 是否属于冻结 Agent 工作流。
     *
     * @param definitionId 定义 ID
     * @return 是否冻结定义
     */
    public boolean isFrozen(String definitionId) {
        return definitionId != null && definitionId.startsWith(PREFIX);
    }

    private String sha256(String content) {
        try {
            return HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256")
                    .digest(content.getBytes(StandardCharsets.UTF_8)));
        } catch (NoSuchAlgorithmException exception) {
            throw new IllegalStateException("SHA-256 is unavailable", exception);
        }
    }
}
