import { Component, Input, Output, EventEmitter, computed, signal, ChangeDetectionStrategy, ViewEncapsulation, OnInit, OnChanges, SimpleChanges } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SyntaxHighlighterService } from '../../services/syntax-highlighter.service';
import { CodeThemeService, CodeTheme } from '../../services/theme.service';
import { CopyButtonDirective } from '../../directives/copy-button.directive';

export type CodeSnippetSize = 'sm' | 'md' | 'lg';

@Component({
  selector: 'ui-code-snippet',
  standalone: true,
  imports: [CommonModule, CopyButtonDirective],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  template: `
    <div [class]="containerClasses()">
      @if (title || showLanguage || copyable) {
        <div class="code-snippet__header">
          @if (title) {
            <span class="code-snippet__title">{{ title }}</span>
          }
          
          <div class="code-snippet__actions">
            @if (showLanguage && finalLanguage()) {
              <span class="code-snippet__language-badge">{{ finalLanguage() }}</span>
            }
            
            @if (copyable) {
              <button 
                type="button"
                class="code-snippet__copy-btn"
                [uiCopyButton]="code"
                [attr.aria-label]="'Copy code to clipboard'"
                title="Copy code">
                <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
                  <path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/>
                </svg>
              </button>
            }
          </div>
        </div>
      }
      
      <div class="code-snippet__content">
        <pre [class]="preClasses()">
          @if (showLineNumbers && lineCount() > 1) {
            <div class="code-snippet__line-numbers" [attr.aria-hidden]="true">
              @for (lineNum of lineNumbers(); track lineNum) {
                <span 
                  class="code-snippet__line-number"
                  [class.code-snippet__line-number--highlighted]="isLineHighlighted(lineNum)">
                  {{ lineNum }}
                </span>
              }
            </div>
          }
          
          <code 
            [class]="codeClasses()"
            [innerHTML]="highlightedCode()">
          </code>
        </pre>
      </div>
      
      @if (maxHeight && !expanded() && isOverflowing()) {
        <div class="code-snippet__expand">
          <button 
            type="button"
            class="code-snippet__expand-btn"
            (click)="toggleExpanded()"
            [attr.aria-expanded]="expanded()">
            Show {{ isOverflowing() ? 'more' : 'less' }}
          </button>
        </div>
      }
    </div>
  `,
  styleUrl: './code-snippet.component.scss'
})
export class CodeSnippetComponent implements OnInit, OnChanges {
  @Input() code = '';
  @Input() language = '';
  @Input() title = '';
  @Input() theme: CodeTheme | null = null;
  @Input() size: CodeSnippetSize = 'md';
  @Input() showLineNumbers = false;
  @Input() copyable = true;
  @Input() showLanguage = true;
  @Input() highlightLines: (number | string)[] = [];
  @Input() maxHeight: string | null = null;
  @Input() wrap = false;
  @Input() startLineNumber = 1;

  @Output() codeChange = new EventEmitter<string>();
  @Output() languageChange = new EventEmitter<string>();

  readonly expanded = signal(false);

  constructor(
    private syntaxHighlighter: SyntaxHighlighterService,
    private themeService: CodeThemeService
  ) {}

  readonly finalLanguage = computed(() => {
    if (this.language) {
      return this.language;
    }
    return this.syntaxHighlighter.detectLanguage(this.code);
  });

  readonly highlightedCode = signal('');

  private async updateHighlightedCode() {
    if (!this.code) {
      this.highlightedCode.set('');
      return;
    }
    
    const lang = this.finalLanguage();
    try {
      const highlighted = await this.syntaxHighlighter.highlight(this.code, {
        language: lang,
        lineNumbers: this.showLineNumbers,
        highlightLines: this.highlightLines
      });
      this.highlightedCode.set(highlighted);
    } catch (error) {
      console.warn('Failed to highlight code:', error);
      this.highlightedCode.set(this.escapeHtml(this.code));
    }
  }

  readonly lineCount = computed(() => {
    return this.code ? this.code.split('\n').length : 0;
  });

  readonly lineNumbers = computed(() => {
    const count = this.lineCount();
    return Array.from({ length: count }, (_, i) => i + this.startLineNumber);
  });

  readonly currentTheme = computed(() => {
    return this.theme || this.themeService.theme();
  });

  readonly containerClasses = computed(() => {
    const classes = ['code-snippet'];
    classes.push(`code-snippet--${this.size}`);
    classes.push(`code-theme-${this.currentTheme()}`);
    
    if (this.wrap) classes.push('code-snippet--wrap');
    if (this.maxHeight && !this.expanded()) classes.push('code-snippet--constrained');
    
    return classes.join(' ');
  });

  readonly preClasses = computed(() => {
    const classes = ['code-snippet__pre'];
    if (this.showLineNumbers && this.lineCount() > 1) {
      classes.push('code-snippet__pre--with-line-numbers');
    }
    return classes.join(' ');
  });

  readonly codeClasses = computed(() => {
    const classes = ['code-snippet__code'];
    classes.push(`language-${this.finalLanguage()}`);
    return classes.join(' ');
  });

  isLineHighlighted(lineNumber: number): boolean {
    return this.highlightLines.some(highlight => {
      if (typeof highlight === 'number') {
        return highlight === lineNumber;
      }
      
      // Handle range format like "5-10"
      const range = highlight.toString().split('-');
      if (range.length === 2) {
        const start = parseInt(range[0], 10);
        const end = parseInt(range[1], 10);
        return lineNumber >= start && lineNumber <= end;
      }
      
      return false;
    });
  }

  isOverflowing(): boolean {
    // This would need to be implemented with ViewChild and element measurements
    // For now, return true if content is long
    return this.lineCount() > 20;
  }

  toggleExpanded(): void {
    this.expanded.update(val => !val);
  }

  ngOnInit(): void {
    this.updateHighlightedCode();
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes['code'] || changes['language']) {
      this.updateHighlightedCode();
    }
  }

  private escapeHtml(text: string): string {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
  }
}