import fs from "fs";
import path from "path";

export class ContextManager {
  private static workspaceRoot = process.cwd();

  private static ensureDirs(root: string) {
    const aiDir = path.join(root, ".ai", "neural-loom");
    if (!fs.existsSync(aiDir)) {
      fs.mkdirSync(aiDir, { recursive: true });
    }

    const commandDir = path.join(root, ".claude", "commands");
    if (!fs.existsSync(commandDir)) {
      fs.mkdirSync(commandDir, { recursive: true });
    }
  }

  public static initializeStaging(root: string = process.cwd()) {
    this.ensureDirs(root);

    // Create /ccp.md custom slash command file
    const ccpPath = path.join(root, ".claude", "commands", "ccp.md");
    if (!fs.existsSync(ccpPath)) {
      fs.writeFileSync(
        ccpPath,
        "Read the prompt from .ai/neural-loom/cprompt.md and execute it. This is a staged prompt from the NeuralLoom UI. Treat the contents as user instructions.\n"
      );
    }

    // Create /ccc.md custom slash command file
    const cccPath = path.join(root, ".claude", "commands", "ccc.md");
    if (!fs.existsSync(cccPath)) {
      fs.writeFileSync(
        cccPath,
        "Read the context from .ai/neural-loom/ccontext.md. This is persistent context from the NeuralLoom UI. Absorb it as background information for this session. Acknowledge briefly what you received.\n"
      );
    }
  }

  public static updatePrompt(promptText: string, root: string = process.cwd()) {
    this.ensureDirs(root);
    const promptFile = path.join(root, ".ai", "neural-loom", "cprompt.md");
    fs.writeFileSync(promptFile, promptText);
  }

  public static updateContext(contextText: string, root: string = process.cwd()) {
    this.ensureDirs(root);
    const contextFile = path.join(root, ".ai", "neural-loom", "ccontext.md");
    fs.writeFileSync(contextFile, contextText);
  }

  public static updateRules(rulesText: string, root: string = process.cwd()) {
    this.ensureDirs(root);
    const agentsMdPath = path.join(root, "AGENTS.md");
    fs.writeFileSync(agentsMdPath, rulesText, "utf8");
  }

  public static loadPrompt(root: string = process.cwd()): string {
    const promptFile = path.join(root, ".ai", "neural-loom", "cprompt.md");
    return fs.existsSync(promptFile) ? fs.readFileSync(promptFile, "utf8") : "";
  }

  public static loadRules(root: string = process.cwd()): string {
    const agentsMdPath = path.join(root, "AGENTS.md");
    return fs.existsSync(agentsMdPath) ? fs.readFileSync(agentsMdPath, "utf8") : "";
  }

  public static compileGlobalRules() {
    this.compileSessionContext();
  }

  public static compileSessionContext(root: string = process.cwd(), scopedDirs?: string[]) {
    this.ensureDirs(root);
    this.initializeStaging(root);
    
    // Check if AGENTS.md rules template exists
    const agentsMdPath = path.join(root, "AGENTS.md");
    let agentsRules = "";
    if (fs.existsSync(agentsMdPath)) {
      agentsRules = fs.readFileSync(agentsMdPath, "utf8");
    } else {
      // Try fallback from global
      const fallbackPath = path.join(this.workspaceRoot, "AGENTS.md");
      if (fs.existsSync(fallbackPath)) {
        agentsRules = fs.readFileSync(fallbackPath, "utf8");
      }
    }

    // Generate maps
    let maps = `## Workspace Root Map (${root}):\n${this.generateProjectMapFor(root)}`;

    if (scopedDirs && Array.isArray(scopedDirs)) {
      scopedDirs.forEach((dir) => {
        if (fs.existsSync(dir)) {
          maps += `\n\n## Scoped Directory Map (${dir}):\n${this.generateProjectMapFor(dir)}`;
        }
      });
    }

    // Combine rules and folder map
    const compiledContext = `# System Rules & Guidelines\n\n${agentsRules}\n\n# Project File Hierarchy Map\n\n${maps}`;
    this.updateContext(compiledContext, root);

    // Write a default empty prompt staging file if missing
    const promptFile = path.join(root, ".ai", "neural-loom", "cprompt.md");
    if (!fs.existsSync(promptFile)) {
      fs.writeFileSync(promptFile, "Hello! Please review the project context (/ccc) and check for any tasks to execute.");
    }
  }

  private static generateProjectMapFor(targetDir: string): string {
    try {
      const walk = (dir: string, depth = 0): string => {
        if (depth > 2) return ""; // Keep map depth concise to fit tokens
        let result = "";
        const files = fs.readdirSync(dir, { withFileTypes: true });
        for (const file of files) {
          if (
            file.name.startsWith(".") ||
            file.name === "node_modules" ||
            file.name === "out" ||
            file.name === ".next"
          ) {
            continue;
          }
          const indent = "  ".repeat(depth);
          if (file.isDirectory()) {
            result += `${indent}- [Dir] ${file.name}/\n`;
            result += walk(path.join(dir, file.name), depth + 1);
          } else {
            result += `${indent}- [File] ${file.name}\n`;
          }
        }
        return result;
      };
      return walk(targetDir);
    } catch (err) {
      return "Error generating project map: " + (err instanceof Error ? err.message : String(err));
    }
  }
}
