#!/usr/bin/env node

const fs = require("fs");
const path = require("path");

const { applyConfig } = require("./apply-config");
const {
  DEFAULT_CONFIG_PATH,
  CONFIG_SECTIONS,
  SECTION_METADATA,
  loadConfig,
  saveConfig,
  ensureConfigStructure,
  countEnabledItems,
  getAllAvailableItems
} = require("./config-manager");

const CONFIG_FLAG_ALIASES = ["--config", "-c"];
const CONTEXT_WARNING_CHAR_LIMIT = {
  instructions: 90000,
  prompts: 45000,
  chatmodes: 30000
};

const numberFormatter = new Intl.NumberFormat("en-US");

const commands = {
  init: {
    description: "Initialize a new project with awesome-copilot configuration",
    usage: "awesome-copilot init [config-file]",
    action: async (args) => {
      const configFile = args[0] || DEFAULT_CONFIG_PATH;
      const { initializeProject } = require("./initialize-project");
      await initializeProject(configFile);
    }
  },

  apply: {
    description: "Apply configuration and copy files to project",
    usage: "awesome-copilot apply [config-file]",
    action: async (args) => {
      const configFile = args[0] || DEFAULT_CONFIG_PATH;
      await applyConfig(configFile);
    }
  },

  list: {
    description: "List items in the configuration with their enabled status",
    usage: "awesome-copilot list [section] [--config <file>]",
    action: (args) => {
      handleListCommand(args);
    }
  },

  toggle: {
    description: "Enable or disable prompts, instructions, chat modes, or collections",
    usage: "awesome-copilot toggle <section> <name|all> [on|off] [--all] [--apply] [--config <file>]",
    action: async (args) => {
      await handleToggleCommand(args);
    }
  },

  reset: {
    description: "Reset .awesome-copilot directory (remove all files but keep structure)",
    usage: "awesome-copilot reset [config-file]",
    action: (args) => {
      handleResetCommand(args);
    }
  },

  help: {
    description: "Show help information",
    usage: "awesome-copilot help",
    action: () => {
      showHelp();
    }
  }
};

function showHelp() {
  console.log("🤖 Awesome GitHub Copilot Configuration Tool");
  console.log("=".repeat(50));
  console.log("");
  console.log("Usage: awesome-copilot <command> [options]");
  console.log("");
  console.log("Commands:");

  for (const [name, cmd] of Object.entries(commands)) {
    console.log(`  ${name.padEnd(10)} ${cmd.description}`);
    console.log(`  ${" ".repeat(10)} ${cmd.usage}`);
    console.log("");
  }

  console.log("Examples:");
  console.log("  awesome-copilot init                          # Create default config file");
  console.log("  awesome-copilot init my-config.yml            # Create named config file");
  console.log("  awesome-copilot apply                         # Apply default config");
  console.log("  awesome-copilot reset                         # Clear .awesome-copilot directory");
  console.log("  awesome-copilot list instructions             # See which instructions are enabled");
  console.log("  awesome-copilot toggle prompts create-readme on  # Enable a specific prompt");
  console.log("  awesome-copilot toggle instructions all off --config team.yml  # Disable all instructions");
  console.log("  awesome-copilot toggle prompts all on --all   # Force enable ALL prompts (override explicit settings)");
  console.log("  awesome-copilot toggle collections testing-automation on --apply  # Enable collection and apply");
  console.log("");
  console.log("Workflow:");
  console.log("  1. Run 'awesome-copilot init' to create a configuration file");
  console.log("  2. Use 'awesome-copilot list' and 'awesome-copilot toggle' to manage enabled items");
  console.log("  3. Run 'awesome-copilot apply' to copy files to your project");
}

function showError(message) {
  console.error(`❌ Error: ${message}`);
  console.log("");
  console.log("Run 'awesome-copilot help' for usage information.");
  process.exit(1);
}

function handleListCommand(rawArgs) {
  const { args, configPath } = extractConfigOption(rawArgs);

  let sectionsToShow = CONFIG_SECTIONS;
  if (args.length > 0) {
    const requestedSection = validateSectionType(args[0]);
    sectionsToShow = [requestedSection];
  }

  const { config } = loadConfig(configPath);
  const sanitizedConfig = ensureConfigStructure(config);

  // Import computeEffectiveItemStates
  const { computeEffectiveItemStates } = require("./config-manager");
  const effectiveStates = computeEffectiveItemStates(sanitizedConfig);

  console.log(`📄 Configuration: ${configPath}`);

  sectionsToShow.forEach(section => {
    const availableItems = getAllAvailableItems(section);
    
    // Count effectively enabled items
    const effectivelyEnabled = Object.values(effectiveStates[section] || {})
      .filter(state => state.enabled).length;
    
    const { totalCharacters } = calculateSectionFootprint(section, sanitizedConfig[section]);
    const headingParts = [
      `${SECTION_METADATA[section].label} (${effectivelyEnabled}/${availableItems.length} enabled)`
    ];

    if (totalCharacters > 0 && section !== "collections") {
      headingParts.push(`~${formatNumber(totalCharacters)} chars`);
    }

    console.log(`\n${headingParts.join(", ")}`);

    if (!availableItems.length) {
      console.log("  (no items available)");
      return;
    }

    // Show items with effective state and reason
    if (section === "collections") {
      // Collections show simple enabled/disabled
      availableItems.forEach(itemName => {
        const isEnabled = Boolean(sanitizedConfig[section]?.[itemName]);
        console.log(`  [${isEnabled ? "✓" : " "}] ${itemName}`);
      });
    } else {
      // Other sections show effective state with reason
      availableItems.forEach(itemName => {
        const effectiveState = effectiveStates[section]?.[itemName];
        if (effectiveState) {
          const symbol = effectiveState.enabled ? "✓" : " ";
          const reasonText = effectiveState.reason === "explicit" 
            ? ` (${effectiveState.reason})`
            : effectiveState.enabled ? ` (${effectiveState.reason})` : "";
          console.log(`  [${symbol}] ${itemName}${reasonText}`);
        } else {
          console.log(`  [ ] ${itemName}`);
        }
      });
    }
  });

  console.log("\nUse 'awesome-copilot toggle' to enable or disable specific items.");
}

async function handleToggleCommand(rawArgs) {
  const { args, configPath, flags } = extractToggleOptions(rawArgs);

  if (args.length < 2) {
    throw new Error("Usage: awesome-copilot toggle <section> <name|all> [on|off] [--all] [--apply] [--config <file>]");
  }

  const section = validateSectionType(args[0]);
  let itemName = args[1];
  const stateArg = args[2];
  const desiredState = stateArg ? parseStateToken(stateArg) : null;
  
  // Handle --all flag
  if (flags.all) {
    itemName = "all";
  }

  const availableItems = getAllAvailableItems(section);
  const availableSet = new Set(availableItems);
  if (!availableItems.length) {
    throw new Error(`No ${SECTION_METADATA[section].label.toLowerCase()} available to toggle.`);
  }

  const { config, header } = loadConfig(configPath);
  const configCopy = {
    ...config,
    [section]: { ...config[section] }
  };
  const sectionState = configCopy[section];

  // Special handling for collections to show delta summary
  if (section === "collections") {
    if (!availableSet.has(itemName)) {
      const suggestion = findClosestMatch(itemName, availableItems);
      if (suggestion) {
        throw new Error(`Unknown ${SECTION_METADATA[section].singular} '${itemName}'. Did you mean '${suggestion}'?`);
      }
      throw new Error(`Unknown ${SECTION_METADATA[section].singular} '${itemName}'.`);
    }

    const currentState = Boolean(sectionState[itemName]);
    const newState = desiredState === null ? !currentState : desiredState;
    
    // Show delta summary for collections
    if (currentState !== newState) {
      const { computeEffectiveItemStates } = require("./config-manager");
      
      // Compute effective states before change
      const effectiveStatesBefore = computeEffectiveItemStates(configCopy);
      
      // Simulate the change
      configCopy[section][itemName] = newState;
      const effectiveStatesAfter = computeEffectiveItemStates(configCopy);
      
      // Calculate delta
      const delta = { enabled: [], disabled: [] };
      for (const sectionName of ["prompts", "instructions", "chatmodes"]) {
        for (const item of getAllAvailableItems(sectionName)) {
          const beforeState = effectiveStatesBefore[sectionName]?.[item]?.enabled || false;
          const afterState = effectiveStatesAfter[sectionName]?.[item]?.enabled || false;
          
          if (!beforeState && afterState) {
            delta.enabled.push(`${sectionName}/${item}`);
          } else if (beforeState && !afterState) {
            delta.disabled.push(`${sectionName}/${item}`);
          }
        }
      }
      
      console.log(`${newState ? "Enabled" : "Disabled"} collection '${itemName}'.`);
      
      if (delta.enabled.length > 0 || delta.disabled.length > 0) {
        console.log("\nDelta summary:");
        if (delta.enabled.length > 0) {
          console.log(`  📈 ${delta.enabled.length} items will be enabled:`);
          delta.enabled.forEach(item => console.log(`    + ${item}`));
        }
        if (delta.disabled.length > 0) {
          console.log(`  📉 ${delta.disabled.length} items will be disabled:`);
          delta.disabled.forEach(item => console.log(`    - ${item}`));
        }
      } else {
        console.log("  No effective changes (items may have explicit overrides)");
      }
    } else {
      console.log(`Collection '${itemName}' is already ${currentState ? "enabled" : "disabled"}.`);
    }
    
    sectionState[itemName] = newState;
  } else if (itemName === "all") {
    if (desiredState === null) {
      throw new Error("Specify 'on' or 'off' when toggling all items.");
    }
    
    // Enhanced --all behavior: override ALL items, even explicit ones
    if (flags.all) {
      console.log(`${desiredState ? "Force-enabling" : "Force-disabling"} ALL ${SECTION_METADATA[section].label.toLowerCase()} (including explicit overrides).`);
      availableItems.forEach(item => {
        sectionState[item] = desiredState;
      });
    } else {
      // Regular "all" behavior: set all items explicitly but respect that they are now explicit
      availableItems.forEach(item => {
        sectionState[item] = desiredState;
      });
      console.log(`${desiredState ? "Enabled" : "Disabled"} all ${SECTION_METADATA[section].label.toLowerCase()}.`);
    }

    if (section === "instructions" && desiredState) {
      console.log("⚠️  Enabling every instruction can exceed Copilot Agent's context window. Consider enabling only what you need.");
    }
  } else {
    if (!availableSet.has(itemName)) {
      const suggestion = findClosestMatch(itemName, availableItems);
      if (suggestion) {
        throw new Error(`Unknown ${SECTION_METADATA[section].singular} '${itemName}'. Did you mean '${suggestion}'?`);
      }
      throw new Error(`Unknown ${SECTION_METADATA[section].singular} '${itemName}'.`);
    }

    const currentState = Boolean(sectionState[itemName]);
    const newState = desiredState === null ? !currentState : desiredState;
    sectionState[itemName] = newState;
    console.log(`${newState ? "Enabled" : "Disabled"} ${SECTION_METADATA[section].singular} '${itemName}'.`);
  }

  const sanitizedConfig = ensureConfigStructure(configCopy);
  saveConfig(configPath, sanitizedConfig, header);

  const enabledCount = countEnabledItems(sanitizedConfig[section]);
  const totalAvailable = availableItems.length;
  const { totalCharacters } = calculateSectionFootprint(section, sanitizedConfig[section]);

  console.log(`\n${SECTION_METADATA[section].label}: ${enabledCount}/${totalAvailable} enabled.`);
  if (totalCharacters > 0 && section !== "collections") {
    console.log(`Estimated ${SECTION_METADATA[section].label.toLowerCase()} context size: ${formatNumber(totalCharacters)} characters.`);
  }
  maybeWarnAboutContext(section, totalCharacters);
  
  // Handle automatic application
  if (flags.apply) {
    console.log("\n🔄 Applying configuration automatically...");
    await applyConfig(configPath);
  } else {
    console.log("Run 'awesome-copilot apply' to copy updated selections into your project.");
  }
}

function extractToggleOptions(rawArgs) {
  const args = [...rawArgs];
  let configPath = DEFAULT_CONFIG_PATH;
  const flags = {
    all: false,
    apply: false
  };

  // Process flags
  for (let i = args.length - 1; i >= 0; i--) {
    const arg = args[i];
    
    if (arg === "--all") {
      flags.all = true;
      args.splice(i, 1);
    } else if (arg === "--apply") {
      flags.apply = true;
      args.splice(i, 1);
    } else if (CONFIG_FLAG_ALIASES.includes(arg)) {
      if (i === args.length - 1) {
        throw new Error("Missing configuration file after --config flag.");
      }
      configPath = args[i + 1];
      args.splice(i, 2);
    }
  }

  // Check for config file as last argument
  if (args.length > 0) {
    const potentialPath = args[args.length - 1];
    if (isConfigFilePath(potentialPath)) {
      configPath = potentialPath;
      args.pop();
    }
  }

  return { args, configPath, flags };
}

function extractConfigOption(rawArgs) {
  const args = [...rawArgs];
  let configPath = DEFAULT_CONFIG_PATH;

  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    if (CONFIG_FLAG_ALIASES.includes(arg)) {
      if (i === args.length - 1) {
        throw new Error("Missing configuration file after --config flag.");
      }
      configPath = args[i + 1];
      args.splice(i, 2);
      i -= 1;
    }
  }

  if (args.length > 0) {
    const potentialPath = args[args.length - 1];
    if (isConfigFilePath(potentialPath)) {
      configPath = potentialPath;
      args.pop();
    }
  }

  return { args, configPath };
}

function isConfigFilePath(value) {
  if (typeof value !== "string") {
    return false;
  }
  return value.endsWith(".yml") || value.endsWith(".yaml") || value.includes("/") || value.includes("\\");
}

function validateSectionType(input) {
  const normalized = String(input || "").toLowerCase();
  if (!SECTION_METADATA[normalized]) {
    throw new Error(`Unknown section '${input}'. Expected one of: ${CONFIG_SECTIONS.join(", ")}.`);
  }
  return normalized;
}

function parseStateToken(token) {
  const normalized = token.toLowerCase();
  if (["on", "enable", "enabled", "true", "yes", "y"].includes(normalized)) {
    return true;
  }
  if (["off", "disable", "disabled", "false", "no", "n"].includes(normalized)) {
    return false;
  }
  throw new Error("State must be 'on' or 'off'.");
}

function calculateSectionFootprint(section, state = {}) {
  const meta = SECTION_METADATA[section];
  if (!meta || section === "collections") {
    return { totalCharacters: 0 };
  }

  let totalCharacters = 0;

  for (const [name, enabled] of Object.entries(state)) {
    if (!enabled) continue;

    const filePath = path.join(__dirname, meta.dir, `${name}${meta.ext}`);
    try {
      const stats = fs.statSync(filePath);
      totalCharacters += stats.size;
    } catch (error) {
      // If the file no longer exists we skip it but continue gracefully.
    }
  }

  return { totalCharacters };
}

function maybeWarnAboutContext(section, totalCharacters) {
  const limit = CONTEXT_WARNING_CHAR_LIMIT[section];
  if (!limit || totalCharacters <= 0) {
    return;
  }

  if (totalCharacters >= limit) {
    console.log(`⚠️  Warning: Estimated ${SECTION_METADATA[section].label.toLowerCase()} size ${formatNumber(totalCharacters)} characters exceeds the recommended limit of ${formatNumber(limit)} characters. Copilot Agent may truncate or crash.`);
  } else if (totalCharacters >= limit * 0.8) {
    console.log(`⚠️  Heads up: Estimated ${SECTION_METADATA[section].label.toLowerCase()} size ${formatNumber(totalCharacters)} characters is approaching the recommended limit (${formatNumber(limit)} characters).`);
  }
}

function formatNumber(value) {
  return numberFormatter.format(Math.round(value));
}

function findClosestMatch(target, candidates) {
  const normalizedTarget = target.toLowerCase();
  return candidates.find(candidate => candidate.toLowerCase().includes(normalizedTarget));
}

function handleResetCommand(rawArgs) {
  const { args, configPath } = extractConfigOption(rawArgs);
  
  const { config } = loadConfig(configPath);
  const outputDir = config.project?.output_directory || ".awesome-copilot";
  
  if (!fs.existsSync(outputDir)) {
    console.log(`📁 Directory ${outputDir} does not exist - nothing to reset.`);
    return;
  }
  
  console.log(`🔄 Resetting ${outputDir} directory...`);
  
  let removedCount = 0;
  
  // Remove all files from subdirectories but keep the directory structure
  const subdirs = ["prompts", "instructions", "chatmodes"];
  for (const subdir of subdirs) {
    const subdirPath = path.join(outputDir, subdir);
    if (fs.existsSync(subdirPath)) {
      const files = fs.readdirSync(subdirPath);
      for (const file of files) {
        const filePath = path.join(subdirPath, file);
        if (fs.statSync(filePath).isFile()) {
          fs.unlinkSync(filePath);
          removedCount++;
          console.log(`🗑️  Removed: ${subdir}/${file}`);
        }
      }
    }
  }
  
  // Remove README.md if it exists
  const readmePath = path.join(outputDir, "README.md");
  if (fs.existsSync(readmePath)) {
    fs.unlinkSync(readmePath);
    removedCount++;
    console.log(`🗑️  Removed: README.md`);
  }
  
  console.log(`\n✅ Reset complete! Removed ${removedCount} files.`);
  console.log(`📁 Directory structure preserved: ${outputDir}/`);
  console.log("Run 'awesome-copilot apply' to repopulate with current configuration.");
}

async function main() {
  const args = process.argv.slice(2);

  if (args.length === 0) {
    showHelp();
    return;
  }

  const command = args[0];
  const commandArgs = args.slice(1);

  if (!commands[command]) {
    showError(`Unknown command: ${command}`);
  }

  try {
    await commands[command].action(commandArgs);
  } catch (error) {
    showError(error.message);
  }
}

if (require.main === module) {
  main();
}

module.exports = { main };
