"use strict";

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

const {
  PACKAGE_NAME,
  GLOBAL_CLAUDE_DIR,
  LEGACY_PACKAGE_NAME,
} = require("./constants");
const { log, logHeader, logSuccess, logError } = require("./logging");
const { writeSettingsAtomic } = require("./fs-utils");

const ECK_STYLE_VALUES = [
  "standard",
  "guided",
  "concise",
  "pair",
  "review",
  "evolv-standard",
  "evolv-guided",
  "evolv-concise",
];

const ECK_STYLE_FILES = ECK_STYLE_VALUES.map((v) => `${v}.md`);

// ─── Pure Settings Stripper ──────────────────────────────────────────────────

function stripECKSettings(settings) {
  const result = JSON.parse(JSON.stringify(settings));
  let stripped = 0;

  if (
    result.statusLine &&
    result.statusLine.command &&
    result.statusLine.command.includes("evolv-")
  ) {
    delete result.statusLine;
    stripped++;
  }

  if (result.hooks && typeof result.hooks === "object") {
    for (const event of Object.keys(result.hooks)) {
      if (!Array.isArray(result.hooks[event])) continue;
      result.hooks[event] = result.hooks[event].filter((entry) => {
        if (Array.isArray(entry.hooks)) {
          const before = entry.hooks.length;
          entry.hooks = entry.hooks.filter(
            (h) => !(h.command && h.command.includes("evolv-")),
          );
          const removed = before - entry.hooks.length;
          if (entry.hooks.length === 0) {
            stripped++;
            return false;
          }
          if (removed > 0) {
            stripped++;
          }
          return true;
        }
        if (entry.command && entry.command.includes("evolv-")) {
          stripped++;
          return false;
        }
        return true;
      });
      if (result.hooks[event].length === 0) {
        delete result.hooks[event];
      }
    }
    if (Object.keys(result.hooks).length === 0) {
      delete result.hooks;
    }
  }

  if (result.spinnerVerbs !== undefined) {
    delete result.spinnerVerbs;
    stripped++;
  }

  if (result.companyAnnouncements !== undefined) {
    delete result.companyAnnouncements;
    stripped++;
  }

  if (
    result.outputStyle &&
    typeof result.outputStyle === "string" &&
    ECK_STYLE_VALUES.includes(result.outputStyle)
  ) {
    delete result.outputStyle;
    stripped++;
  }

  if (result.showTurnDuration !== undefined) {
    delete result.showTurnDuration;
    stripped++;
  }

  if (result.terminalProgressBarEnabled !== undefined) {
    delete result.terminalProgressBarEnabled;
    stripped++;
  }

  return { settings: result, stripped };
}

// ─── Legacy Cleanup ─────────────────────────────────────────────────────────

function cleanupLegacy({ dryRun = false, globalDir = GLOBAL_CLAUDE_DIR } = {}) {
  logHeader("Legacy Cleanup");
  log(`Removing ${LEGACY_PACKAGE_NAME} artifacts from ~/.claude/`);
  log("");

  let dirs = 0;
  let files = 0;
  let settingsEntries = 0;

  // 1. Remove ~/.claude/claude-code-kit/ directory
  const legacyKitDir = path.join(globalDir, "claude-code-kit");
  try {
    if (fs.existsSync(legacyKitDir)) {
      if (dryRun) {
        logSuccess(`Would remove ${legacyKitDir}`);
      } else {
        fs.rmSync(legacyKitDir, { recursive: true, force: true });
        logSuccess(`Removed ${legacyKitDir}`);
      }
      dirs++;
    }
  } catch (err) {
    logError(`Could not remove ${legacyKitDir}: ${err.message}`);
  }

  // 2. Remove ~/.claude/skills/evolv-* directories
  const skillsDir = path.join(globalDir, "skills");
  try {
    if (fs.existsSync(skillsDir)) {
      const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
      for (const entry of entries) {
        if (entry.isDirectory() && entry.name.startsWith("evolv-")) {
          const dirPath = path.join(skillsDir, entry.name);
          try {
            if (dryRun) {
              logSuccess(`Would remove skill: ${entry.name}`);
            } else {
              fs.rmSync(dirPath, { recursive: true, force: true });
              logSuccess(`Removed skill: ${entry.name}`);
            }
            dirs++;
          } catch (err) {
            logError(`Could not remove ${dirPath}: ${err.message}`);
          }
        }
      }
    }
  } catch (err) {
    logError(`Could not scan skills directory: ${err.message}`);
  }

  // 3. Remove ~/.claude/hooks/evolv-* files
  const hooksDir = path.join(globalDir, "hooks");
  try {
    if (fs.existsSync(hooksDir)) {
      const entries = fs.readdirSync(hooksDir);
      for (const entry of entries) {
        if (entry.startsWith("evolv-")) {
          const filePath = path.join(hooksDir, entry);
          try {
            if (dryRun) {
              logSuccess(`Would remove hook: ${entry}`);
            } else {
              fs.rmSync(filePath, { force: true });
              logSuccess(`Removed hook: ${entry}`);
            }
            files++;
          } catch (err) {
            logError(`Could not remove ${filePath}: ${err.message}`);
          }
        }
      }
    }
  } catch (err) {
    logError(`Could not scan hooks directory: ${err.message}`);
  }

  // 4. Clean settings.json entries
  const settingsPath = path.join(globalDir, "settings.json");
  try {
    if (fs.existsSync(settingsPath)) {
      let settings;
      try {
        settings = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
      } catch {
        log("  settings.json is not valid JSON — skipping settings cleanup");
        settings = null;
      }

      if (settings) {
        let changed = false;

        // Remove statusLine if it references evolv-
        if (
          settings.statusLine &&
          settings.statusLine.command &&
          settings.statusLine.command.includes("evolv-")
        ) {
          if (dryRun) {
            logSuccess("Would remove statusLine entry");
          } else {
            delete settings.statusLine;
            logSuccess("Removed statusLine entry");
          }
          settingsEntries++;
          changed = true;
        }

        // Remove hook entries where command includes evolv-
        if (settings.hooks) {
          for (const event of Object.keys(settings.hooks)) {
            if (!Array.isArray(settings.hooks[event])) continue;
            settings.hooks[event] = settings.hooks[event].filter((entry) => {
              // Check matcher-wrapper format
              if (Array.isArray(entry.hooks)) {
                const hasEvolv = entry.hooks.some(
                  (h) => h.command && h.command.includes("evolv-"),
                );
                if (hasEvolv) {
                  settingsEntries++;
                  changed = true;
                  if (dryRun) {
                    logSuccess(`Would remove ${event} hook entry`);
                  } else {
                    logSuccess(`Removed ${event} hook entry`);
                  }
                  return false;
                }
              }
              // Check bare format
              if (entry.command && entry.command.includes("evolv-")) {
                settingsEntries++;
                changed = true;
                if (dryRun) {
                  logSuccess(`Would remove ${event} hook entry`);
                } else {
                  logSuccess(`Removed ${event} hook entry`);
                }
                return false;
              }
              return true;
            });
            // Clean up empty arrays
            if (settings.hooks[event].length === 0) {
              delete settings.hooks[event];
            }
          }
          // Clean up empty hooks object
          if (Object.keys(settings.hooks).length === 0) {
            delete settings.hooks;
          }
        }

        if (changed && !dryRun) {
          writeSettingsAtomic(settingsPath, settings);
        }
      }
    }
  } catch (err) {
    logError(`Could not clean settings.json: ${err.message}`);
  }

  // 5. Suggest npm uninstall
  log("");
  log(`To complete cleanup, run:`);
  log(`  npm uninstall -g ${LEGACY_PACKAGE_NAME}`);
  log("");

  const total = dirs + files + settingsEntries;
  if (total === 0) {
    log("No legacy artifacts found.");
  } else {
    log(
      `${dryRun ? "Would remove" : "Removed"}: ${dirs} director${dirs === 1 ? "y" : "ies"}, ${files} file${files !== 1 ? "s" : ""}, ${settingsEntries} settings entr${settingsEntries === 1 ? "y" : "ies"}`,
    );
  }

  return { dirs, files, settingsEntries };
}

// ─── Uninstall ──────────────────────────────────────────────────────────────

function uninstallGlobal({
  dryRun = false,
  globalDir = GLOBAL_CLAUDE_DIR,
} = {}) {
  logHeader("Uninstall evolv Coder Kit");
  log("Removing ECK-owned files from ~/.claude/ (user files preserved)");
  log("");

  let dirs = 0;
  let files = 0;
  let settingsEntries = 0;

  const verb = dryRun ? "Would remove" : "Removed";

  // 1. Remove ~/.claude/skills/eck-* directories
  const skillsDir = path.join(globalDir, "skills");
  try {
    if (fs.existsSync(skillsDir)) {
      const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
      for (const entry of entries) {
        if (entry.isDirectory() && entry.name.startsWith("eck-")) {
          const dirPath = path.join(skillsDir, entry.name);
          try {
            if (!dryRun) {
              fs.rmSync(dirPath, { recursive: true, force: true });
            }
            logSuccess(`${verb} skill: ${entry.name}`);
            dirs++;
          } catch (err) {
            logError(`Could not remove ${dirPath}: ${err.message}`);
          }
        }
      }
    }
  } catch (err) {
    logError(`Could not scan skills directory: ${err.message}`);
  }

  // 2. Remove ~/.claude/evolv-coder-kit/ directory (scaffold + migration state)
  const kitDir = path.join(globalDir, "evolv-coder-kit");
  try {
    if (fs.existsSync(kitDir)) {
      if (!dryRun) {
        fs.rmSync(kitDir, { recursive: true, force: true });
      }
      logSuccess(`${verb} ${kitDir}`);
      dirs++;
    }
  } catch (err) {
    logError(`Could not remove ${kitDir}: ${err.message}`);
  }

  // 3. Remove ~/.claude/hooks/evolv-* files
  const hooksDir = path.join(globalDir, "hooks");
  try {
    if (fs.existsSync(hooksDir)) {
      const entries = fs.readdirSync(hooksDir);
      for (const entry of entries) {
        if (entry.startsWith("evolv-")) {
          const filePath = path.join(hooksDir, entry);
          try {
            if (!dryRun) {
              fs.rmSync(filePath, { force: true });
            }
            logSuccess(`${verb} hook: ${entry}`);
            files++;
          } catch (err) {
            logError(`Could not remove ${filePath}: ${err.message}`);
          }
        }
      }
    }
  } catch (err) {
    logError(`Could not scan hooks directory: ${err.message}`);
  }

  // 4. Remove ECK-owned output mode files
  const stylesDir = path.join(globalDir, "output-modes");
  try {
    if (fs.existsSync(stylesDir)) {
      const entries = fs.readdirSync(stylesDir);
      for (const entry of entries) {
        if (ECK_STYLE_FILES.includes(entry)) {
          const filePath = path.join(stylesDir, entry);
          try {
            if (!dryRun) {
              fs.rmSync(filePath, { force: true });
            }
            logSuccess(`${verb} output mode: ${entry}`);
            files++;
          } catch (err) {
            logError(`Could not remove ${filePath}: ${err.message}`);
          }
        }
      }
    }
  } catch (err) {
    logError(`Could not scan output-modes directory: ${err.message}`);
  }

  // 5. Clean ECK-owned settings.json entries
  const settingsPath = path.join(globalDir, "settings.json");
  try {
    if (fs.existsSync(settingsPath)) {
      let rawSettings;
      try {
        rawSettings = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
      } catch {
        log("  settings.json is not valid JSON — skipping settings cleanup");
        rawSettings = null;
      }

      if (rawSettings) {
        const { settings: stripped, stripped: count } =
          stripECKSettings(rawSettings);
        settingsEntries += count;

        if (count > 0) {
          if (dryRun) {
            logSuccess(`${verb} ${count} settings entries`);
          } else {
            writeSettingsAtomic(settingsPath, stripped);
            logSuccess(`${verb} ${count} settings entries`);
          }
        }
      }
    }
  } catch (err) {
    logError(`Could not clean settings.json: ${err.message}`);
  }

  // 6. Remove ~/.claude/evolv-coder-standards/ directory
  const standardsDir = path.join(globalDir, "evolv-coder-standards");
  try {
    if (fs.existsSync(standardsDir)) {
      if (!dryRun) {
        fs.rmSync(standardsDir, { recursive: true, force: true });
      }
      logSuccess(`${verb} ${standardsDir}`);
      dirs++;
    }
  } catch (err) {
    logError(`Could not remove ${standardsDir}: ${err.message}`);
  }

  log("");
  const total = dirs + files + settingsEntries;
  if (total === 0) {
    log("No ECK artifacts found — nothing to remove.");
  } else {
    log(
      `${dryRun ? "Would remove" : "Removed"}: ${dirs} director${dirs === 1 ? "y" : "ies"}, ${files} file${files !== 1 ? "s" : ""}, ${settingsEntries} settings entr${settingsEntries === 1 ? "y" : "ies"}`,
    );
  }

  if (!dryRun) {
    log("");
    log("To complete removal, run:");
    log(`  npm uninstall -g ${PACKAGE_NAME}`);
  }

  return { dirs, files, settingsEntries };
}

module.exports = {
  cleanupLegacy,
  uninstallGlobal,
  stripECKSettings,
  ECK_STYLE_VALUES,
  ECK_STYLE_FILES,
};
