#!/usr/bin/env node
/**
 * VS Code Configuration Validator
 *
 * Validates that VS Code 1.109 orchestration settings are correctly configured:
 * 1. Required settings exist in devcontainer.json
 * 2. Extensions.json includes all required extensions
 * 3. Devcontainer.json extension drift is explicitly allowlisted
 */

import { readFileSync, existsSync } from "fs";
import { resolve, dirname } from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const REPO_ROOT = resolve(__dirname, "..");

// Required VS Code 1.109 settings
const REQUIRED_SETTINGS = [
  "chat.customAgentInSubagent.enabled",
  "chat.agentFilesLocations",
  "chat.agentSkillsLocations",
  "chat.useAgentSkills",
];

// Required extensions for full orchestration support
const REQUIRED_EXTENSIONS = [
  "GitHub.copilot-chat",
  "ms-azuretools.vscode-azure-mcp-server",
  "ms-azuretools.vscode-bicep",
  "DavidAnson.vscode-markdownlint",
];

// Extensions intentionally installed only in devcontainer.json.
// Keep this list explicit and minimal to avoid silent drift.
const ALLOWED_DEVCONTAINER_ONLY_EXTENSIONS = new Set([
  "github.vscode-github-actions",
  "pomdtr.excalidraw-editor",
  "mechatroner.rainbow-csv",
  "ms-azuretools.azure-dev",
  "ms-azuretools.vscode-azurecontainerapps",
  "ms-azuretools.vscode-azurestaticwebapps",
  "ms-azuretools.vscode-containers",
  "ms-kubernetes-tools.vscode-aks-tools",
  "ms-kubernetes-tools.vscode-kubernetes-tools",
  "ms-vscode.vscode-node-azure-pack",
  "mutantdino.resourcemonitor",
]);

let errors = [];
let warnings = [];

function normalizeExtensionId(extensionId) {
  return String(extensionId || "")
    .trim()
    .toLowerCase();
}

function findDuplicateExtensions(extensions) {
  const counts = new Map();
  for (const extension of extensions) {
    const key = normalizeExtensionId(extension);
    counts.set(key, (counts.get(key) || 0) + 1);
  }
  return [...counts.entries()]
    .filter(([, count]) => count > 1)
    .map(([id]) => id)
    .sort();
}

function checkRequiredExtensionsInList(sourceName, extensions) {
  const normalized = new Set(extensions.map(normalizeExtensionId));
  for (const requiredExtension of REQUIRED_EXTENSIONS) {
    if (!normalized.has(normalizeExtensionId(requiredExtension))) {
      errors.push(
        `❌ Missing required extension in ${sourceName}: ${requiredExtension}`,
      );
    }
  }
}

/**
 * Parse JSON with comments (JSONC) - handles devcontainer.json format
 */
import { parseJsonc } from "./_lib/parse-jsonc.mjs";

/**
 * Check devcontainer.json for required settings
 */
function validateDevcontainer() {
  const devcontainerPath = resolve(
    REPO_ROOT,
    ".devcontainer/devcontainer.json",
  );

  if (!existsSync(devcontainerPath)) {
    errors.push("❌ .devcontainer/devcontainer.json not found");
    return;
  }

  console.log("📋 Checking devcontainer.json...");

  try {
    const content = readFileSync(devcontainerPath, "utf-8");
    const config = parseJsonc(content);

    const settings = config?.customizations?.vscode?.settings || {};
    const extensions = config?.customizations?.vscode?.extensions || [];

    // Check required settings
    for (const setting of REQUIRED_SETTINGS) {
      if (!(setting in settings)) {
        errors.push(`❌ Missing required setting: ${setting}`);
      } else {
        console.log(`   ✓ ${setting}`);
      }
    }

    // Check if subagent setting is true
    if (settings["chat.customAgentInSubagent.enabled"] !== true) {
      errors.push(
        "❌ chat.customAgentInSubagent.enabled must be true for Orchestrator",
      );
    }

    // Check agent paths
    const agentPaths = settings["chat.agentFilesLocations"] || {};
    if (!agentPaths[".github/agents"]) {
      warnings.push("⚠️  .github/agents not in chat.agentFilesLocations");
    }
    if (!agentPaths[".github/agents/_subagents"]) {
      warnings.push(
        "⚠️  .github/agents/_subagents not in chat.agentFilesLocations",
      );
    }

    // Check skills path
    const skillPaths = settings["chat.agentSkillsLocations"] || {};
    if (!skillPaths[".github/skills"]) {
      warnings.push("⚠️  .github/skills not in chat.agentSkillsLocations");
    }

    checkRequiredExtensionsInList("devcontainer.json", extensions);

    const duplicates = findDuplicateExtensions(extensions);
    for (const duplicate of duplicates) {
      warnings.push(
        `⚠️  Duplicate extension in devcontainer.json: ${duplicate}`,
      );
    }

    return extensions;
  } catch (e) {
    errors.push(`❌ Failed to parse devcontainer.json: ${e.message}`);
    return [];
  }
}

/**
 * Check extensions.json for required extensions
 */
function validateExtensions() {
  const extensionsPath = resolve(REPO_ROOT, ".vscode/extensions.json");

  if (!existsSync(extensionsPath)) {
    warnings.push(
      "⚠️  .vscode/extensions.json not found (optional but recommended)",
    );
    return [];
  }

  console.log("\n📦 Checking extensions.json...");

  try {
    const content = readFileSync(extensionsPath, "utf-8");
    const config = JSON.parse(content);
    const recommendations = config?.recommendations || [];

    checkRequiredExtensionsInList("extensions.json", recommendations);

    for (const ext of REQUIRED_EXTENSIONS) {
      const found = recommendations.some(
        (r) => normalizeExtensionId(r) === normalizeExtensionId(ext),
      );
      if (found) {
        console.log(`   ✓ ${ext}`);
      }
    }

    const duplicates = findDuplicateExtensions(recommendations);
    for (const duplicate of duplicates) {
      warnings.push(`⚠️  Duplicate extension in extensions.json: ${duplicate}`);
    }

    return recommendations;
  } catch (e) {
    errors.push(`❌ Failed to parse extensions.json: ${e.message}`);
    return [];
  }
}

/**
 * Cross-check devcontainer extensions with extensions.json
 */
function crossCheckExtensions(devcontainerExts, extensionsJsonExts) {
  if (devcontainerExts.length === 0 || extensionsJsonExts.length === 0) {
    return;
  }

  console.log("\n🔗 Cross-checking extension lists...");

  const devSet = new Set(devcontainerExts.map(normalizeExtensionId));
  const extSet = new Set(extensionsJsonExts.map(normalizeExtensionId));

  const onlyInDevcontainer = [...devSet]
    .filter((extension) => !extSet.has(extension))
    .sort();
  const onlyInExtensionsJson = [...extSet]
    .filter((extension) => !devSet.has(extension))
    .sort();

  for (const extension of onlyInDevcontainer) {
    if (!ALLOWED_DEVCONTAINER_ONLY_EXTENSIONS.has(extension)) {
      errors.push(
        `❌ Non-allowlisted extension only in devcontainer.json: ${extension}`,
      );
    }
  }

  for (const extension of onlyInExtensionsJson) {
    errors.push(`❌ Extension only in extensions.json: ${extension}`);
  }

  const allowlistedPresent = onlyInDevcontainer.filter((extension) =>
    ALLOWED_DEVCONTAINER_ONLY_EXTENSIONS.has(extension),
  );
  for (const extension of allowlistedPresent) {
    console.log(`   ℹ allowlisted devcontainer-only extension: ${extension}`);
  }

  console.log(
    `   ✓ ${devcontainerExts.length} extensions in devcontainer.json`,
  );
  console.log(
    `   ✓ ${extensionsJsonExts.length} extensions in extensions.json`,
  );
}

// Main execution
console.log("🔍 VS Code 1.109 Configuration Validator\n");
console.log("=".repeat(50) + "\n");

const devcontainerExts = validateDevcontainer();
const extensionsJsonExts = validateExtensions();
crossCheckExtensions(devcontainerExts, extensionsJsonExts);

// Summary
console.log("\n" + "=".repeat(50));
console.log("📊 Validation Summary\n");

if (warnings.length > 0) {
  console.log("Warnings:");
  warnings.forEach((w) => console.log("  " + w));
}

if (errors.length > 0) {
  console.log("\nErrors:");
  errors.forEach((e) => console.log("  " + e));
  console.log("\n❌ Validation FAILED with " + errors.length + " error(s)");
  console.log("\n🔧 Remediation:");
  console.log("   1. Review devcontainer.json customizations.vscode.settings");
  console.log("   2. Ensure all required VS Code 1.109 settings are present");
  console.log("   3. Check .vscode/extensions.json for recommended extensions");
  process.exit(1);
} else {
  console.log("\n✅ VS Code configuration is valid for 1.109 orchestration");
  process.exit(0);
}
