import fs from "fs";
import path from "path";
import type { IPty } from "node-pty";
import { AgentRunner, RunnerStatus } from "./AgentRunner";
import { SessionPersister } from "./SessionPersister";

function isWindows(): boolean {
  const key = "platform";
  return (process as unknown as Record<string, unknown>)[key] === "win32";
}

function findGitBash(): string | null {
  if (!isWindows()) {
    return "bash";
  }
  const pf = process.env.PROGRAMFILES || "C:\\Program Files";
  const pf86 = process.env["PROGRAMFILES(X86)"] || "C:\\Program Files (x86)";
  const local = process.env.LOCALAPPDATA || "";

  const candidates: string[] = [
    process.env.WINGMAN_BASH_PATH,
    path.join(pf, "Git", "bin", "bash.exe"),
    path.join(pf86, "Git", "bin", "bash.exe"),
    local ? path.join(local, "Programs", "Git", "bin", "bash.exe") : "",
  ].filter((p): p is string => typeof p === "string" && p !== "");

  return candidates.find(p => fs.existsSync(p)) || null;
}

interface SSHConfig {
  host: string;
  username: string;
  privateKeyPath?: string;
  port?: number;
}

export class SSHRunner extends AgentRunner {
  id: string;
  name: string;
  type: 'mock' | 'claude' | 'claude-docker' | 'claude-ssh' | 'aider' | 'aider-docker' = 'claude-ssh';
  status: 'idle' | 'running' | 'stopped' = 'idle';
  createdAt: string;
  logs: string[] = [];

  private ptyProcess: IPty | null = null;
  private ptyModule: typeof import("node-pty") | null = null;

  constructor(id: string, name?: string) {
    super();
    this.id = id;
    this.name = name || `SSH Session ${id.substring(0, 8)}`;
    this.createdAt = new Date().toISOString();
  }

  private appendLog(line: string) {
    this.logs.push(line);
    if (this.logs.length > 5000) {
      this.logs.shift();
    }
    this.parseTokenUsage(line);
    this.emitOutput(line);
    SessionPersister.saveSession(this);
  }

  async start(): Promise<void> {
    if (this.status === 'running') return;

    this.status = 'running';
    this.appendLog("\x1b[1;35m==================================================\x1b[0m\r\n");
    this.appendLog("\x1b[1;36m       NEURALLOOM REMOTE VM (SSH) ROUTE BRIDGE     \x1b[0m\r\n");
    this.appendLog("\x1b[1;35m==================================================\x1b[0m\r\n");
    this.appendLog("[System] Loading SSH configuration...\r\n");

    const bashPath = findGitBash();
    if (!bashPath) {
      this.status = 'stopped';
      this.appendLog("\x1b[1;31m[System Error] Git Bash not found. Cannot bootstrap SSH terminal.\x1b[0m\r\n");
      return;
    }

    const configPath = path.join(process.cwd(), ".ai", "neural-loom", "ssh.json");
    if (!fs.existsSync(configPath)) {
      this.status = 'stopped';
      this.appendLog("\x1b[1;31m[Configuration Error] ssh.json not found!\x1b[0m\r\n");
      this.appendLog(`\x1b[1;33mPlease create the SSH credentials file at: ${configPath}\x1b[0m\r\n`);
      this.appendLog("\x1b[1;36mTemplate structure:\x1b[0m\r\n");
      this.appendLog(
        JSON.stringify(
          {
            host: "your.remote.host.com",
            username: "dave",
            privateKeyPath: "C:\\\\Users\\\\Dave\\\\.ssh\\\\id_rsa",
            port: 22,
          },
          null,
          2
        ).replace(/\n/g, "\r\n") + "\r\n"
      );
      this.appendLog("\x1b[1;31m[System] SSH startup aborted.\x1b[0m\r\n");
      return;
    }

    try {
      const rawConfig = fs.readFileSync(configPath, "utf8");
      const config: SSHConfig = JSON.parse(rawConfig);

      if (!config.host || !config.username) {
        this.status = 'stopped';
        this.appendLog("\x1b[1;31m[System Error] Invalid ssh.json configuration. 'host' and 'username' are required.\x1b[0m\r\n");
        return;
      }

      if (!this.ptyModule) {
        this.ptyModule = await import("node-pty");
      }

      this.appendLog(`[System] Connecting to ${config.username}@${config.host}...\r\n`);

      const portOpt = config.port ? `-p ${config.port}` : "";
      const keyOpt = config.privateKeyPath ? `-i "${config.privateKeyPath}"` : "";
      
      const sshCmd = `ssh -t ${keyOpt} ${portOpt} ${config.username}@${config.host} "claude --agents-md"`;

      this.ptyProcess = this.ptyModule.spawn(bashPath, ["-c", sshCmd], {
        name: "xterm-256color",
        cols: 120,
        rows: 30,
        cwd: process.cwd(),
        env: {
          ...process.env,
          TERM: "xterm-256color",
          COLORTERM: "truecolor",
        },
      });

      this.ptyProcess.onData((data: string) => {
        this.appendLog(data);
      });

      this.ptyProcess.onExit(({ exitCode, signal }: { exitCode: number; signal?: number }) => {
        this.status = 'stopped';
        this.appendLog(`\r\n\x1b[1;31m[System] SSH Session exited (code=${exitCode}, signal=${signal}).\x1b[0m\r\n`);
        this.ptyProcess = null;
      });

    } catch (err) {
      const errorMessage = err instanceof Error ? err.message : "Unknown error";
      this.status = 'stopped';
      this.appendLog(`\x1b[1;31m[System Error] SSH connection failed: ${errorMessage}\x1b[0m\r\n`);
    }
  }

  async stop(): Promise<void> {
    this.status = 'stopped';
    if (this.ptyProcess) {
      try {
        this.ptyProcess.kill();
      } catch (err) {
        console.error("Error killing SSH PTY process:", err);
      }
      this.ptyProcess = null;
    }
    this.appendLog("\r\n\x1b[1;31m[System] SSH Connection terminated.\x1b[0m\r\n");
  }

  async sendInput(text: string, isRaw = false): Promise<void> {
    if (this.status !== 'running' || !this.ptyProcess) {
      this.appendLog(`\r\n\x1b[1;31m[Error] Cannot write: SSH session is ${this.status}.\x1b[0m\r\n`);
      return;
    }

    this.ptyProcess.write(isRaw ? text : text + "\r");
  }

  getStatus(): RunnerStatus {
    return {
      id: this.id,
      name: this.name,
      type: this.type,
      status: this.status,
      createdAt: this.createdAt,
      logsCount: this.logs.length,
      workspaceRoot: this.workspaceRoot,
      scopedDirs: this.scopedDirs,
      tokenUsage: this.tokenUsage
    };
  }
}
