package com.agent.management.engine;

import com.agent.management.model.entity.Workflow;
import com.agent.management.repository.WorkflowRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Stream;

/**
 * 启动时一次性迁移：把所有工作流及其版本快照中节点 type 规范化为 camelCase 首字母小写。
 *
 * <p>迁移对象：</p>
 * <ol>
 *   <li>{@code workflows.json} 中每条 workflow 的 graphData</li>
 *   <li>{@code {run-dir 父目录}/workflow-versions/{id}/_versions/v{n}/workflow.json} 快照文件</li>
 * </ol>
 *
 * <p>幂等：已规范化的数据不会触发写入；启动再次运行也是安全的。</p>
 */
@Slf4j
@Component
@Order(20) // 在 Repository initMaxId 之后运行
@RequiredArgsConstructor
public class WorkflowDataMigrationRunner implements ApplicationRunner {

    private final WorkflowRepository workflowRepo;

    @Value("${workflow.run-dir:./data/workflow-runs}")
    private String runDir;

    @Override
    public void run(ApplicationArguments args) {
        int workflowMigrated = migrateWorkflows();
        int snapshotMigrated = migrateVersionSnapshots();
        if (workflowMigrated > 0 || snapshotMigrated > 0) {
            log.info("[Migration] 节点 type 规范化完成: workflows={}, snapshots={}",
                    workflowMigrated, snapshotMigrated);
        } else {
            log.debug("[Migration] 节点 type 已全部规范化，无需迁移");
        }
    }

    /** 扫描 workflows.json，规范化每条 workflow.graphData */
    private int migrateWorkflows() {
        try {
            List<Workflow> all = workflowRepo.findAll();
            int migrated = 0;
            for (Workflow wf : all) {
                String original = wf.getGraphData();
                if (original == null || original.isBlank()) continue;
                if (!NodeTypeUtils.isNormalized(original)) {
                    wf.setGraphData(NodeTypeUtils.normalizeGraphData(original));
                    workflowRepo.save(wf);
                    migrated++;
                    log.info("[Migration] 工作流 [{}] {} graphData 已规范化", wf.getId(), wf.getName());
                }
            }
            return migrated;
        } catch (Exception e) {
            log.warn("[Migration] 扫描 workflows 失败: {}", e.getMessage(), e);
            return 0;
        }
    }

    /** 扫描所有 workflow 版本快照文件，规范化其中的 graphData */
    private int migrateVersionSnapshots() {
        Path runPath = Paths.get(runDir).toAbsolutePath();
        Path versionRoot = runPath.getParent().resolve("workflow-versions");
        if (!Files.isDirectory(versionRoot)) return 0;

        int migrated = 0;
        // 遍历 workflow-versions/{workflowId}/_versions/v{n}/workflow.json
        try (Stream<Path> wfIdDirs = Files.list(versionRoot)) {
            for (Path wfIdDir : wfIdDirs.toList()) {
                Path versionsDir = wfIdDir.resolve("_versions");
                if (!Files.isDirectory(versionsDir)) continue;
                try (Stream<Path> versionDirs = Files.list(versionsDir)) {
                    for (Path versionDir : versionDirs.toList()) {
                        Path snapshot = versionDir.resolve("workflow.json");
                        if (Files.isRegularFile(snapshot)) {
                            migrated += migrateSnapshotFile(snapshot);
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn("[Migration] 扫描版本快照失败: {}", e.getMessage(), e);
        }
        return migrated;
    }

    /** 规范化单个快照文件；已规范化的返回 0，发生变更返回 1 */
    @SuppressWarnings("unchecked")
    private int migrateSnapshotFile(Path snapshotFile) {
        try {
            String content = Files.readString(snapshotFile, StandardCharsets.UTF_8);
            // 快照格式: { "graphData": "...", "name": "...", "savedAt": "..." }
            // graphData 是字符串字段，需要二次解析
            var mapper = new com.fasterxml.jackson.databind.ObjectMapper();
            var root = mapper.readTree(content);
            String graphData = root.path("graphData").asText(null);
            if (graphData == null || NodeTypeUtils.isNormalized(graphData)) return 0;

            String normalizedGraph = NodeTypeUtils.normalizeGraphData(graphData);
            var mutable = root.deepCopy();
            ((com.fasterxml.jackson.databind.node.ObjectNode) mutable).put("graphData", normalizedGraph);

            String newContent = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(mutable);
            Files.writeString(snapshotFile, newContent, StandardCharsets.UTF_8);
            log.info("[Migration] 版本快照已规范化: {}", snapshotFile);
            return 1;
        } catch (Exception e) {
            log.warn("[Migration] 处理快照失败 {}: {}", snapshotFile, e.getMessage());
            return 0;
        }
    }
}
