import {
  DeesElement,
  property,
  html,
  customElement,
  type TemplateResult,
  css,
  cssManager,
} from '@design.estate/dees-element';
import type { Terminal } from 'xterm';
import type { FitAddon } from 'xterm-addon-fit';
import { themeDefaultStyles } from '../../00theme.js';
import { DeesServiceLibLoader } from '../../../services/index.js';

declare global {
  interface HTMLElementTagNameMap {
    'dees-workspace-terminal-preview': DeesWorkspaceTerminalPreview;
  }
}

/**
 * A read-only terminal preview component using xterm.js for rendering.
 * Used during workspace initialization to show onInit command progress.
 */
@customElement('dees-workspace-terminal-preview')
export class DeesWorkspaceTerminalPreview extends DeesElement {
  public static demo = () => html`
    <dees-workspace-terminal-preview
      .command=${'pnpm install'}
      .lines=${[
        'Packages: +42',
        'Progress: resolved 142, reused 140, downloaded 2, added 42, done',
        '',
        'dependencies:',
        '+ @push.rocks/smartpromise 4.2.3',
        '+ typescript 5.3.3',
        '',
        'Done in 2.3s'
      ]}
    ></dees-workspace-terminal-preview>
  `;
  public static demoGroup = 'Workspace';

  /**
   * The command being displayed (shown in header)
   */
  @property({ type: String })
  accessor command: string = '';

  /**
   * Output lines to display
   */
  @property({ type: Array })
  accessor lines: string[] = [];

  private terminal: Terminal | null = null;
  private fitAddon: FitAddon | null = null;
  private lastLineCount: number = 0;
  private resizeObserver: ResizeObserver | null = null;
  private terminalThemeSubscription: any = null;

  public static styles = [
    themeDefaultStyles,
    cssManager.defaultStyles,
    css`
      :host {
        display: block;
        height: 200px;
      }

      .terminal-preview {
        height: 100%;
        border-radius: 8px;
        overflow: hidden;
        background: ${cssManager.bdTheme('#ffffff', '#000000')};
        border: 1px solid ${cssManager.bdTheme('hsl(0 0% 85%)', 'hsl(0 0% 20%)')};
        display: flex;
        flex-direction: column;
      }

      .terminal-header {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 8px 12px;
        background: ${cssManager.bdTheme('hsl(0 0% 96%)', 'hsl(0 0% 10%)')};
        font-size: 12px;
        font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace;
        color: ${cssManager.bdTheme('hsl(0 0% 40%)', 'hsl(0 0% 60%)')};
        border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 85%)', 'hsl(0 0% 20%)')};
        flex-shrink: 0;
      }

      .terminal-header-icon {
        color: ${cssManager.bdTheme('hsl(0 0% 50%)', 'hsl(0 0% 50%)')};
      }

      .terminal-header-command {
        color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 80%)')};
        font-weight: 500;
      }

      .terminal-container {
        flex: 1;
        position: relative;
        padding: 8px;
      }

      #xterm-container {
        position: absolute;
        top: 8px;
        left: 8px;
        right: 8px;
        bottom: 8px;
      }

      /* xterm.js styles */
      .xterm {
        font-feature-settings: 'liga' 0;
        position: relative;
        user-select: none;
        -ms-user-select: none;
        -webkit-user-select: none;
      }

      .xterm.focus,
      .xterm:focus {
        outline: none;
      }

      .xterm .xterm-helpers {
        position: absolute;
        top: 0;
        z-index: 5;
      }

      .xterm .xterm-helper-textarea {
        padding: 0;
        border: 0;
        margin: 0;
        position: absolute;
        opacity: 0;
        left: -9999em;
        top: 0;
        width: 0;
        height: 0;
        z-index: -5;
        white-space: nowrap;
        overflow: hidden;
        resize: none;
      }

      .xterm .composition-view {
        background: ${cssManager.bdTheme('#ffffff', '#000000')};
        color: ${cssManager.bdTheme('#333333', '#ffffff')};
        display: none;
        position: absolute;
        white-space: nowrap;
        z-index: 1;
      }

      .xterm .composition-view.active {
        display: block;
      }

      .xterm .xterm-viewport {
        background-color: ${cssManager.bdTheme('#ffffff', '#000000')};
        overflow-y: scroll;
        cursor: default;
        position: absolute;
        right: 0;
        left: 0;
        top: 0;
        bottom: 0;
      }

      .xterm .xterm-screen {
        position: relative;
      }

      .xterm .xterm-screen canvas {
        position: absolute;
        left: 0;
        top: 0;
      }

      .xterm .xterm-scroll-area {
        visibility: hidden;
      }

      .xterm-char-measure-element {
        display: inline-block;
        visibility: hidden;
        position: absolute;
        top: 0;
        left: -9999em;
        line-height: normal;
      }

      .xterm {
        cursor: text;
      }

      .xterm.enable-mouse-events {
        cursor: default;
      }

      .xterm.xterm-cursor-pointer {
        cursor: pointer;
      }

      .xterm.column-select.focus {
        cursor: crosshair;
      }

      .xterm .xterm-accessibility,
      .xterm .xterm-message {
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        right: 0;
        z-index: 10;
        color: transparent;
      }

      .xterm .live-region {
        position: absolute;
        left: -9999px;
        width: 1px;
        height: 1px;
        overflow: hidden;
      }

      .xterm-dim {
        opacity: 0.5;
      }

      .xterm-underline {
        text-decoration: underline;
      }

      /* Custom scrollbar for xterm viewport */
      .xterm .xterm-viewport::-webkit-scrollbar {
        width: 8px;
      }

      .xterm .xterm-viewport::-webkit-scrollbar-track {
        background: ${cssManager.bdTheme('hsl(0 0% 96%)', 'hsl(0 0% 8%)')};
      }

      .xterm .xterm-viewport::-webkit-scrollbar-thumb {
        background: ${cssManager.bdTheme('hsl(0 0% 80%)', 'hsl(0 0% 25%)')};
        border-radius: 4px;
      }

      .xterm .xterm-viewport::-webkit-scrollbar-thumb:hover {
        background: ${cssManager.bdTheme('hsl(0 0% 70%)', 'hsl(0 0% 35%)')};
      }
    `,
  ];

  public render(): TemplateResult {
    return html`
      <div class="terminal-preview">
        <div class="terminal-header">
          <span class="terminal-header-icon">$</span>
          <span class="terminal-header-command">${this.command || 'Waiting...'}</span>
        </div>
        <div class="terminal-container">
          <div id="xterm-container"></div>
        </div>
      </div>
    `;
  }

  /**
   * Get terminal theme colors based on bright/dark mode
   */
  private getTerminalTheme(isBright: boolean) {
    return isBright
      ? {
          background: '#ffffff',
          foreground: '#333333',
          cursor: '#333333',
          cursorAccent: '#ffffff',
          selectionBackground: 'rgba(0, 0, 0, 0.2)',
        }
      : {
          background: '#000000',
          foreground: '#cccccc',
          cursor: '#cccccc',
          cursorAccent: '#000000',
          selectionBackground: 'rgba(255, 255, 255, 0.2)',
        };
  }

  public async firstUpdated(
    _changedProperties: Map<string | number | symbol, unknown>
  ): Promise<void> {
    super.firstUpdated(_changedProperties);

    const container = this.shadowRoot?.getElementById('xterm-container');
    if (!container) return;

    // Get current theme from domtools
    const domtoolsInstance = await this.domtoolsPromise;
    const isBright = domtoolsInstance.themeManager.goBrightBoolean;

    // Load xterm from CDN
    const libLoader = DeesServiceLibLoader.getInstance();
    const [xtermBundle, fitAddonBundle] = await Promise.all([
      libLoader.loadXterm(),
      libLoader.loadXtermFitAddon(),
    ]);

    // Create xterm terminal in read-only mode using CDN-loaded module
    this.terminal = new xtermBundle.Terminal({
      convertEol: true,
      cursorBlink: false,
      disableStdin: true,
      fontSize: 12,
      fontFamily: "'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace",
      theme: this.getTerminalTheme(isBright),
      scrollback: 1000,
    });

    // Subscribe to theme changes
    this.terminalThemeSubscription = domtoolsInstance.themeManager.themeObservable.subscribe((goBright: boolean) => {
      if (this.terminal) {
        this.terminal.options.theme = this.getTerminalTheme(goBright);
      }
    });

    this.fitAddon = new fitAddonBundle.FitAddon();
    this.terminal.loadAddon(this.fitAddon);
    this.terminal.open(container);
    this.fitAddon.fit();

    // Set up resize observer to refit terminal
    this.resizeObserver = new ResizeObserver(() => {
      if (this.fitAddon) {
        this.fitAddon.fit();
      }
    });
    this.resizeObserver.observe(container);

    // Write any existing lines
    this.writeNewLines();
  }

  public async updated(changedProperties: Map<string, any>) {
    super.updated(changedProperties);

    if (changedProperties.has('lines')) {
      this.writeNewLines();
    }
  }

  private writeNewLines() {
    if (!this.terminal) return;

    // Write only new lines since last update
    const newLines = this.lines.slice(this.lastLineCount);
    for (const line of newLines) {
      this.terminal.writeln(line);
    }
    this.lastLineCount = this.lines.length;
  }

  public async disconnectedCallback(): Promise<void> {
    if (this.resizeObserver) {
      this.resizeObserver.disconnect();
      this.resizeObserver = null;
    }
    if (this.terminalThemeSubscription) {
      this.terminalThemeSubscription.unsubscribe();
      this.terminalThemeSubscription = null;
    }
    if (this.terminal) {
      this.terminal.dispose();
      this.terminal = null;
    }
    await super.disconnectedCallback();
  }

  /**
   * Add a new line to the output
   */
  public addLine(line: string) {
    this.lines = [...this.lines, line];
  }

  /**
   * Clear all output lines
   */
  public clear() {
    this.lines = [];
    this.lastLineCount = 0;
    if (this.terminal) {
      this.terminal.clear();
    }
  }
}
