import { existsSync, readFileSync, statSync } from "node:fs";
import { join } from "node:path";
import type { MotionDiagnostic } from "../kdl/types.js";

export type FlowAssetId = "flow-01" | "flow-02" | "flow-03" | "flow-04" | "flow-05";

export interface FlowAssetMapping {
  id: FlowAssetId;
  title: string;
  mermaidFile: string;
  pngFile: string;
  tasks: string[];
  evidence: string;
  chapters: string[];
  requiredTerms: string[];
}

export interface FlowAssetCoverageResult {
  ok: boolean;
  rootDir: string;
  assets: Array<FlowAssetMapping & {
    mermaidBytes: number;
    pngBytes: number;
  }>;
  diagnostics: MotionDiagnostic[];
}

export const FLOW_ASSET_MAPPINGS: FlowAssetMapping[] = [
  {
    id: "flow-01",
    title: "总体功能流程",
    mermaidFile: "flow-01.mmd",
    pngFile: "flow-01.png",
    tasks: ["KW-200", "KW-202", "KW-203", "KW-205", "KW-206", "KW-211.1"],
    evidence: "EV-211",
    chapters: ["FLOW 2", "FLOW 5", "FLOW 6"],
    requiredTerms: ["项目资源", "GRL Lexer", "KDL WASM API", "Motion Queue", "Post Processor"]
  },
  {
    id: "flow-02",
    title: "GRL 编译执行流程",
    mermaidFile: "flow-02.mmd",
    pngFile: "flow-02.png",
    tasks: ["KW-100", "KW-101", "KW-110", "KW-202", "KW-203", "KW-204", "KW-211.2"],
    evidence: "EV-211",
    chapters: ["FLOW 3", "GRL 20", "GRL 21"],
    requiredTerms: ["Lexer", "Parser", "Semantic Analyzer", "Executable IR", "Wait Registry"]
  },
  {
    id: "flow-03",
    title: "KDL 计算流程",
    mermaidFile: "flow-03.mmd",
    pngFile: "flow-03.png",
    tasks: ["KW-002", "KW-008", "KW-009", "KW-010", "KW-011", "KW-211.3"],
    evidence: "EV-211",
    chapters: ["FLOW 4", "KDL 11", "KDL 12", "KDL 13", "KDL 14"],
    requiredTerms: ["RobotHandle", "planMoveJ", "planMoveL", "planMoveC", "planPath"]
  },
  {
    id: "flow-04",
    title: "数据传递流程",
    mermaidFile: "flow-04.mmd",
    pngFile: "flow-04.png",
    tasks: ["KW-200", "KW-201", "KW-202", "KW-203", "KW-204", "KW-206", "KW-211.4"],
    evidence: "EV-211",
    chapters: ["FLOW 5", "FLOW 9"],
    requiredTerms: ["Project", "Compile", "KDL", "Runtime", "Output"]
  },
  {
    id: "flow-05",
    title: "诊断传递流程",
    mermaidFile: "flow-05.mmd",
    pngFile: "flow-05.png",
    tasks: ["KW-110", "KW-111", "KW-206", "KW-209", "KW-211.5"],
    evidence: "EV-211",
    chapters: ["FLOW 9", "FLOW 10"],
    requiredTerms: ["Diagnostic", "severity", "sourceMap", "GRL file", "brandSource"]
  }
];

export function validateFlowAssetCoverage(rootDir: string): FlowAssetCoverageResult {
  const diagnostics: MotionDiagnostic[] = [];
  const assets: FlowAssetCoverageResult["assets"] = [];

  for (const mapping of FLOW_ASSET_MAPPINGS) {
    const mermaidPath = join(rootDir, mapping.mermaidFile);
    const pngPath = join(rootDir, mapping.pngFile);
    const mermaidBytes = fileSizeOrDiagnostic(mermaidPath, mapping, "mermaid", diagnostics);
    const pngBytes = fileSizeOrDiagnostic(pngPath, mapping, "png", diagnostics);

    if (mermaidBytes > 0) {
      const source = readFileSync(mermaidPath, "utf8");
      for (const term of mapping.requiredTerms) {
        if (!source.includes(term)) {
          diagnostics.push({
            severity: "error",
            code: "FLOW_REQUIRED_TERM_MISSING",
            message: `${mapping.id} is missing required term ${term}`,
            data: { id: mapping.id, term, file: mapping.mermaidFile }
          });
        }
      }
    }

    if (mapping.tasks.length === 0 || !mapping.tasks.some((task) => task.startsWith("KW-211"))) {
      diagnostics.push({
        severity: "error",
        code: "FLOW_TASK_MAPPING_MISSING",
        message: `${mapping.id} must map to a KW-211 subtask`,
        data: { id: mapping.id }
      });
    }

    assets.push({
      ...mapping,
      mermaidBytes,
      pngBytes
    });
  }

  return {
    ok: diagnostics.every((diagnostic) => diagnostic.severity !== "error"),
    rootDir,
    assets,
    diagnostics
  };
}

function fileSizeOrDiagnostic(
  path: string,
  mapping: FlowAssetMapping,
  kind: "mermaid" | "png",
  diagnostics: MotionDiagnostic[]
): number {
  if (!existsSync(path)) {
    diagnostics.push({
      severity: "error",
      code: "FLOW_ASSET_MISSING",
      message: `${mapping.id} ${kind} asset is missing`,
      data: { id: mapping.id, path }
    });
    return 0;
  }

  const size = statSync(path).size;
  if (size <= 0) {
    diagnostics.push({
      severity: "error",
      code: "FLOW_ASSET_EMPTY",
      message: `${mapping.id} ${kind} asset is empty`,
      data: { id: mapping.id, path }
    });
  }
  return size;
}
