import type { Terminal, ITerminalOptions } from 'xterm';
import type { FitAddon } from 'xterm-addon-fit';
import type { ITerminalTab, ICreateTerminalTabOptions, TTerminalTabType } from './interfaces.js';
import type { IXtermBundle, IXtermFitAddonBundle } from '../../../services/index.js';

/**
 * Manages terminal tabs lifecycle and state
 */
export class TerminalTabManager {
  private tabs: Map<string, ITerminalTab> = new Map();
  private tabCounter: number = 0;
  private xtermBundle: IXtermBundle | null = null;
  private xtermFitAddonBundle: IXtermFitAddonBundle | null = null;

  /**
   * Initialize the manager with loaded xterm modules.
   * Must be called before creating tabs.
   */
  public setXtermModules(xtermBundle: IXtermBundle, fitAddonBundle: IXtermFitAddonBundle): void {
    this.xtermBundle = xtermBundle;
    this.xtermFitAddonBundle = fitAddonBundle;
  }

  /**
   * Generate unique tab ID
   */
  private generateTabId(): string {
    this.tabCounter++;
    return `terminal-${this.tabCounter}-${Date.now()}`;
  }

  /**
   * Get default label for tab type
   */
  private getDefaultLabel(type: TTerminalTabType, metadata?: ITerminalTab['metadata']): string {
    switch (type) {
      case 'shell':
        return 'bash';
      case 'script':
        return metadata?.scriptName || 'script';
      case 'package-update':
        return metadata?.packageName ? `update ${metadata.packageName}` : 'update';
      case 'custom':
        return metadata?.command || 'process';
      default:
        return 'terminal';
    }
  }

  /**
   * Get default icon for tab type
   */
  private getDefaultIcon(type: TTerminalTabType): string {
    switch (type) {
      case 'shell':
        return 'lucide:terminal';
      case 'script':
        return 'lucide:play';
      case 'package-update':
        return 'lucide:packageCheck';
      case 'custom':
        return 'lucide:code';
      default:
        return 'lucide:terminal';
    }
  }

  /**
   * Get terminal theme configuration
   */
  private getTerminalTheme(isBright: boolean): any {
    if (isBright) {
      return {
        background: '#ffffff',
        foreground: '#333333',
        cursor: '#333333',
        cursorAccent: '#ffffff',
        selection: 'rgba(0, 0, 0, 0.2)',
        black: '#000000',
        red: '#cd3131',
        green: '#00bc00',
        yellow: '#949800',
        blue: '#0451a5',
        magenta: '#bc05bc',
        cyan: '#0598bc',
        white: '#555555',
        brightBlack: '#666666',
        brightRed: '#cd3131',
        brightGreen: '#14ce14',
        brightYellow: '#b5ba00',
        brightBlue: '#0451a5',
        brightMagenta: '#bc05bc',
        brightCyan: '#0598bc',
        brightWhite: '#a5a5a5',
      };
    } else {
      return {
        background: '#000000',
        foreground: '#ffffff',
        cursor: '#ffffff',
        cursorAccent: '#000000',
        selection: 'rgba(255, 255, 255, 0.2)',
      };
    }
  }

  /**
   * Create a new tab instance
   */
  createTab(options: ICreateTerminalTabOptions, isBright: boolean): ITerminalTab {
    if (!this.xtermBundle || !this.xtermFitAddonBundle) {
      throw new Error('TerminalTabManager: xterm modules not initialized. Call setXtermModules() first.');
    }

    const id = this.generateTabId();
    const type = options.type;

    // Create xterm.js Terminal instance using CDN-loaded module
    const terminal = new this.xtermBundle.Terminal({
      convertEol: true,
      cursorBlink: true,
      theme: this.getTerminalTheme(isBright),
      fontFamily: 'Menlo, Monaco, "Courier New", monospace',
      fontSize: 13,
      lineHeight: 1.2,
    });

    // Create FitAddon using CDN-loaded module
    const fitAddon = new this.xtermFitAddonBundle.FitAddon();
    terminal.loadAddon(fitAddon);

    const tab: ITerminalTab = {
      id,
      label: options.label || this.getDefaultLabel(type, options.metadata),
      iconName: options.iconName || this.getDefaultIcon(type),
      type,
      closeable: options.closeable ?? (type !== 'shell'),
      terminal,
      fitAddon,
      process: null,
      inputWriter: null,
      exited: false,
      exitCode: null,
      createdAt: Date.now(),
      metadata: options.metadata,
    };

    this.tabs.set(id, tab);
    return tab;
  }

  /**
   * Get tab by ID
   */
  getTab(id: string): ITerminalTab | undefined {
    return this.tabs.get(id);
  }

  /**
   * Get all tabs as array (ordered by creation time)
   */
  getAllTabs(): ITerminalTab[] {
    return Array.from(this.tabs.values()).sort((a, b) => a.createdAt - b.createdAt);
  }

  /**
   * Get the number of tabs
   */
  getTabCount(): number {
    return this.tabs.size;
  }

  /**
   * Check if tab exists
   */
  hasTab(id: string): boolean {
    return this.tabs.has(id);
  }

  /**
   * Close and cleanup a tab
   */
  closeTab(id: string): boolean {
    const tab = this.tabs.get(id);
    if (!tab) return false;

    // Kill process if still running
    if (tab.process && !tab.exited) {
      try {
        tab.process.kill();
      } catch (e) {
        console.warn('Failed to kill process:', e);
      }
    }

    // Dispose terminal
    try {
      tab.terminal.dispose();
    } catch (e) {
      console.warn('Failed to dispose terminal:', e);
    }

    this.tabs.delete(id);
    return true;
  }

  /**
   * Rename a tab
   */
  renameTab(id: string, newLabel: string): boolean {
    const tab = this.tabs.get(id);
    if (!tab) return false;

    tab.label = newLabel;
    return true;
  }

  /**
   * Update tab process state to exited
   */
  markTabExited(id: string, exitCode: number): void {
    const tab = this.tabs.get(id);
    if (!tab) return;

    tab.exited = true;
    tab.exitCode = exitCode;
  }

  /**
   * Set process for a tab
   */
  setTabProcess(id: string, process: ITerminalTab['process'], inputWriter: ITerminalTab['inputWriter']): void {
    const tab = this.tabs.get(id);
    if (!tab) return;

    tab.process = process;
    tab.inputWriter = inputWriter;
  }

  /**
   * Update theme for all terminals
   */
  updateAllThemes(isBright: boolean): void {
    const theme = this.getTerminalTheme(isBright);
    for (const tab of this.tabs.values()) {
      tab.terminal.options.theme = theme;
    }
  }

  /**
   * Dispose all tabs and cleanup
   */
  disposeAll(): void {
    for (const [id] of this.tabs) {
      this.closeTab(id);
    }
    this.tabs.clear();
  }
}
