import * as vscode from "vscode";

const outputChannels = new Map<string, vscode.OutputChannel>();

export class Logger {
  private readonly prefix: string;
  private readonly outputChannel: vscode.OutputChannel;
  private readonly debugOutputChannel: vscode.OutputChannel;

  constructor(prefix: string) {
    this.prefix = prefix;
    // Always use "Codeflash" as the shared channel name
    this.outputChannel = this.getOrCreateOutputChannel("Codeflash");
    this.debugOutputChannel = this.getOrCreateOutputChannel("Codeflash-Debug");
  }

  info(message: string): void {
    this.log("INFO", message);
  }

  warn(message: string): void {
    this.log("WARN", message);
  }

  error(message: string, error?: Error): void {
    const errorDetails = error ? ` - ${error.message}` : "";
    this.log("ERROR", `${message}${errorDetails}`);
    if (error?.stack) {
      this.outputChannel.appendLine(`Stack: ${error.stack}`);
    }
  }

  debug(message: string): void {
    this.log("DEBUG", message);
  }

  get _outputChannel(): vscode.OutputChannel {
    return this.outputChannel;
  }

  private getOrCreateOutputChannel(channelName: string): vscode.OutputChannel {
    if (!outputChannels.has(channelName)) {
      outputChannels.set(
        channelName,
        vscode.window.createOutputChannel(channelName),
      );
    }
    return outputChannels.get(channelName)!;
  }

  private log(level: string, message: string): void {
    const timestamp = new Date().toISOString();

    const hasLspMarker = message.includes("::::");
    const isSendingData = message.toLowerCase().includes("sending data:");

    const isServerLspMessage = hasLspMarker && !isSendingData;
    const isDebug = level === "DEBUG";

    const channel =
      isServerLspMessage || isDebug
        ? this.debugOutputChannel
        : this.outputChannel;

    if (isSendingData) {
      return;
    }

    let component: string;
    if (this.prefix.includes("Extension")) {
      component = "Client";
    } else if (this.prefix === "Codeflash") {
      component = "LSP";
    } else {
      component = this.prefix;
    }

    channel.appendLine(`[${component}] ${timestamp} [${level}]: ${message}`);
  }

  dispose(): void {
    // Don't dispose shared channels - only remove our reference
    // The channel will be disposed when VS Code shuts down
  }
}
