import { access, readdir, readFile } from "node:fs/promises";
import { constants as fsConstants } from "node:fs";
import { join, resolve } from "node:path";

async function exists(path) {
  try {
    await access(path, fsConstants.F_OK);
    return true;
  } catch {
    return false;
  }
}

function parseValidateArgs(args) {
  const parsed = { target: "." };
  let targetSet = false;

  for (const arg of args) {
    if (arg.startsWith("-")) {
      throw new Error(`Unknown option for validate: ${arg}`);
    }
    if (targetSet) {
      throw new Error("Too many positional arguments. Only one target directory is supported.");
    }
    parsed.target = arg;
    targetSet = true;
  }

  return parsed;
}

const REQUIRED_FILES = [
  "AGENTS.md",
  "INSTALL.md",
  "task.md",
  "workflows/brainstorm.md",
  "workflows/write-plan.md",
  "workflows/execute-plan.md",
  "agents/code-reviewer.md",
  "tests/run-tests.sh",
  "tests/check-antigravity-profile.sh",
];

const REQUIRED_SKILLS = [
  "brainstorming",
  "executing-plans",
  "finishing-a-development-branch",
  "receiving-code-review",
  "requesting-code-review",
  "systematic-debugging",
  "test-driven-development",
  "using-git-worktrees",
  "using-superpowers",
  "verification-before-completion",
  "writing-plans",
  "writing-skills",
  "single-flow-task-execution",
];

const LEGACY_PATTERNS = [
  "Skill tool",
  "Task tool with",
  'Task\\("',
  "Dispatch implementer subagent",
  "Dispatch code-reviewer subagent",
  "Create TodoWrite",
  "Mark task complete in TodoWrite",
  "Use TodoWrite",
  "superpowers:",
];

const AGENTS_MAPPINGS = [
  "task_boundary",
  "browser_subagent",
  "view_file",
  "docs/plans/task.md",
  "run_command",
  "grep_search",
  "find_by_name",
];

export async function validateCommand(args, { cwd, stdout, stderr }) {
  let parsed;
  try {
    parsed = parseValidateArgs(args);
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    stderr.write(`${message}\n`);
    return 1;
  }

  const targetDir = resolve(cwd, parsed.target);
  const agentDir = join(targetDir, ".agent");

  if (!(await exists(agentDir))) {
    stderr.write(`No .agent directory found at ${agentDir}\nRun 'antigravity-superpowers init' first.\n`);
    return 1;
  }

  let passCount = 0;
  let failCount = 0;

  function pass(msg) {
    stdout.write(`  [PASS] ${msg}\n`);
    passCount++;
  }

  function fail(msg) {
    stdout.write(`  [FAIL] ${msg}\n`);
    failCount++;
  }

  stdout.write("Checking required files...\n");
  for (const file of REQUIRED_FILES) {
    const filePath = join(agentDir, file);
    if (await exists(filePath)) {
      pass(`File exists: .agent/${file}`);
    } else {
      fail(`Missing file: .agent/${file}`);
    }
  }

  stdout.write("\nChecking required skills...\n");
  for (const skill of REQUIRED_SKILLS) {
    const skillPath = join(agentDir, "skills", skill, "SKILL.md");
    if (await exists(skillPath)) {
      pass(`Skill exists: ${skill}`);
    } else {
      fail(`Missing skill: ${skill}`);
    }
  }

  stdout.write("\nChecking frontmatter...\n");
  for (const skill of REQUIRED_SKILLS) {
    const skillPath = join(agentDir, "skills", skill, "SKILL.md");
    if (!(await exists(skillPath))) continue;

    const content = await readFile(skillPath, "utf8");
    const hasDelimiters = /^---$/m.test(content);
    const hasName = /^name:\s*\S/m.test(content);
    const hasDescription = /^description:\s*\S/m.test(content);

    if (hasDelimiters) pass(`${skill} has frontmatter`);
    else fail(`${skill} missing frontmatter delimiters`);

    if (hasName) pass(`${skill} has name`);
    else fail(`${skill} missing name field`);

    if (hasDescription) pass(`${skill} has description`);
    else fail(`${skill} missing description field`);
  }

  stdout.write("\nChecking for legacy patterns...\n");
  const skillsDir = join(agentDir, "skills");
  let allSkillContent = "";
  if (await exists(skillsDir)) {
    const skills = await readdir(skillsDir, { withFileTypes: true });
    for (const entry of skills) {
      if (!entry.isDirectory()) continue;
      const skillFile = join(skillsDir, entry.name, "SKILL.md");
      if (await exists(skillFile)) {
        allSkillContent += await readFile(skillFile, "utf8");
      }
    }
  }

  for (const pattern of LEGACY_PATTERNS) {
    const regex = new RegExp(pattern);
    if (regex.test(allSkillContent)) {
      fail(`Legacy pattern found: ${pattern}`);
    } else {
      pass(`Legacy pattern absent: ${pattern}`);
    }
  }

  stdout.write("\nChecking AGENTS mapping contract...\n");
  const agentsPath = join(agentDir, "AGENTS.md");
  if (await exists(agentsPath)) {
    const agentsContent = await readFile(agentsPath, "utf8");
    for (const mapping of AGENTS_MAPPINGS) {
      if (agentsContent.includes(mapping)) {
        pass(`AGENTS includes: ${mapping}`);
      } else {
        fail(`AGENTS missing: ${mapping}`);
      }
    }
  } else {
    fail("AGENTS.md not found");
  }

  // Check runtime tracker is NOT bundled
  const runtimeTracker = join(targetDir, "docs", "plans", "task.md");
  if (!(await exists(runtimeTracker))) {
    pass("Runtime tracker not bundled (created at runtime)");
  } else {
    // It's OK if user created it during runtime, don't fail
    pass("Runtime tracker exists (created by skill flow)");
  }

  stdout.write(`\n  Passed: ${passCount}\n  Failed: ${failCount}\n\n`);

  if (failCount > 0) {
    stdout.write("STATUS: FAILED\n");
    return 1;
  }

  stdout.write("STATUS: PASSED\n");
  return 0;
}
