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

const REPO_URL = "https://github.com/MicrosoftDocs/Agent-Skills.git";
const CLONE_DIR = join(process.env.TMPDIR || "/tmp", "antigravity-azure-skills-cache");

const BUNDLES = {
  "quick-start": [
    "azure-app-service",
    "azure-blob-storage",
    "azure-functions",
    "azure-sql-database",
    "azure-key-vault",
    "azure-app-configuration",
    "azure-microsoft-foundry",
    "azure-monitor",
  ],
  popular: [
    "azure-app-service",
    "azure-blob-storage",
    "azure-cosmos-db",
    "azure-container-registry",
    "azure-functions",
    "azure-sql-database",
    "azure-key-vault",
    "azure-virtual-machines",
    "azure-kubernetes-service",
    "azure-event-grid",
    "azure-service-bus",
    "azure-monitor",
    "azure-app-configuration",
    "azure-resource-manager",
    "azure-cost-management",
    "azure-logic-apps",
    "azure-microsoft-foundry",
    "azure-data-factory",
    "azure-api-management",
    "azure-container-apps",
    "azure-defender-for-cloud",
  ],
  "ai-ml": [
    "azure-ai-services",
    "azure-ai-vision",
    "azure-bot-service",
    "azure-cognitive-search",
    "azure-machine-learning",
    "azure-ai-foundry-local",
    "azure-microsoft-foundry",
    "azure-anomaly-detector",
  ],
  devops: [
    "azure-devops",
    "azure-pipelines",
    "azure-repos",
    "azure-boards",
    "azure-artifacts",
    "azure-test-plans",
    "azure-automation",
    "azure-monitor",
  ],
  security: [
    "azure-key-vault",
    "azure-rbac",
    "azure-policy",
    "azure-sentinel",
    "azure-defender-for-cloud",
    "azure-attestation",
    "azure-confidential-computing",
    "azure-firewall",
  ],
};

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

function parseArgs(args) {
  const parsed = {
    target: ".",
    bundle: null,
    skills: [],
    listBundles: false,
    listSkills: false,
    refresh: false,
  };
  let targetSet = false;

  for (let i = 0; i < args.length; i++) {
    const arg = args[i];

    if (arg === "--bundle" || arg === "-B") {
      parsed.bundle = args[++i];
      if (!parsed.bundle) throw new Error("--bundle requires a bundle name");
      continue;
    }
    if (arg === "--list-bundles") {
      parsed.listBundles = true;
      continue;
    }
    if (arg === "--list-skills") {
      parsed.listSkills = true;
      continue;
    }
    if (arg === "--refresh") {
      parsed.refresh = true;
      continue;
    }
    if (arg === "--skill" || arg === "-s") {
      const skill = args[++i];
      if (!skill) throw new Error("--skill requires a skill name");
      parsed.skills.push(skill);
      continue;
    }
    if (arg.startsWith("-")) {
      throw new Error(`Unknown option: ${arg}`);
    }
    if (targetSet) {
      throw new Error("Too many positional arguments.");
    }
    parsed.target = arg;
    targetSet = true;
  }

  return parsed;
}

function cloneOrUpdate(stdout, refresh) {
  if (refresh && exists(CLONE_DIR)) {
    try {
      execFileSync("rm", ["-rf", CLONE_DIR]);
    } catch {
      // ignore
    }
  }

  const cloneExists =
    (() => {
      try {
        return require("node:fs").existsSync(join(CLONE_DIR, "skills"));
      } catch {
        return false;
      }
    })() ||
    (() => {
      try {
        execFileSync("test", ["-d", join(CLONE_DIR, "skills")]);
        return true;
      } catch {
        return false;
      }
    })();

  if (!cloneExists) {
    stdout.write(`Cloning Microsoft Agent-Skills repository...\n`);
    execFileSync("git", ["clone", "--depth", "1", REPO_URL, CLONE_DIR], {
      stdio: ["ignore", "pipe", "pipe"],
    });
    stdout.write(`Cached at ${CLONE_DIR}\n`);
  } else {
    stdout.write(`Using cached repository at ${CLONE_DIR}\n`);
    stdout.write(`(Use --refresh to re-download)\n`);
  }

  return join(CLONE_DIR, "skills");
}

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

  // List bundles
  if (parsed.listBundles) {
    stdout.write("Available bundles:\n\n");
    for (const [name, skills] of Object.entries(BUNDLES)) {
      stdout.write(`  ${name.padEnd(15)} (${skills.length} skills)\n`);
    }
    stdout.write(`\nUsage: antigravity-superpowers add-azure-skills --bundle <name>\n`);
    return 0;
  }

  // List all available skills
  if (parsed.listSkills) {
    let skillsDir;
    try {
      skillsDir = cloneOrUpdate(stdout, parsed.refresh);
    } catch (error) {
      stderr.write(`Failed to clone repository: ${error.message}\n`);
      return 1;
    }

    const entries = await readdir(skillsDir, { withFileTypes: true });
    const skillNames = entries
      .filter((e) => e.isDirectory())
      .map((e) => e.name)
      .sort();

    stdout.write(`\n${skillNames.length} Azure skills available:\n\n`);
    for (const name of skillNames) {
      stdout.write(`  ${name}\n`);
    }
    stdout.write(
      `\nUsage: antigravity-superpowers add-azure-skills --skill <name> [--skill <name> ...]\n`,
    );
    return 0;
  }

  // Determine which skills to install
  let skillsToInstall = [];

  if (parsed.bundle) {
    const bundleSkills = BUNDLES[parsed.bundle];
    if (!bundleSkills) {
      stderr.write(
        `Unknown bundle: ${parsed.bundle}\nAvailable: ${Object.keys(BUNDLES).join(", ")}\n`,
      );
      return 1;
    }
    skillsToInstall = bundleSkills;
  }

  if (parsed.skills.length > 0) {
    skillsToInstall = [...new Set([...skillsToInstall, ...parsed.skills])];
  }

  if (skillsToInstall.length === 0) {
    stderr.write(
      "No skills specified. Use --bundle <name> or --skill <name>.\n" +
        "Run with --list-bundles or --list-skills to see available options.\n",
    );
    return 1;
  }

  // Clone/update repo
  let skillsDir;
  try {
    skillsDir = cloneOrUpdate(stdout, parsed.refresh);
  } catch (error) {
    stderr.write(`Failed to clone repository: ${error.message}\n`);
    return 1;
  }

  // Resolve target
  const targetDir = resolve(cwd, parsed.target);
  const agentSkillsDir = join(targetDir, ".agent", "skills");

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

  // Copy skills
  let installed = 0;
  let skipped = 0;
  const missing = [];

  for (const skill of skillsToInstall) {
    const src = join(skillsDir, skill);
    const dest = join(agentSkillsDir, skill);

    if (!(await exists(src))) {
      missing.push(skill);
      continue;
    }

    if (await exists(dest)) {
      stdout.write(`  [SKIP] ${skill} (already exists)\n`);
      skipped++;
      continue;
    }

    await cp(src, dest, { recursive: true });
    stdout.write(`  [ADD]  ${skill}\n`);
    installed++;
  }

  stdout.write(`\nInstalled: ${installed}, Skipped: ${skipped}`);
  if (missing.length > 0) {
    stdout.write(`, Not found: ${missing.length}`);
    stderr.write(`\nMissing skills: ${missing.join(", ")}\n`);
  }
  stdout.write(`\n`);

  return missing.length > 0 ? 1 : 0;
}
