import { BaseBlockHandler, type IBlockEventHandlers } from '../block.base.js';
import type { IBlock } from '../../wysiwyg.types.js';
import { cssManager } from '@design.estate/dees-element';
import { WysiwygSelection } from '../../wysiwyg.selection.js';
import type { HLJSApi } from 'highlight.js';
import { cssGeistFontFamily, cssMonoFontFamily } from '../../../../00fonts.js';
import { PROGRAMMING_LANGUAGES } from '../../wysiwyg.constants.js';
import { DeesServiceLibLoader } from '../../../../../services/index.js';

/**
 * CodeBlockHandler with improved architecture
 * 
 * Key features:
 * 1. Simple DOM structure
 * 2. Line number handling
 * 3. Syntax highlighting only when not focused (grey text while editing)
 * 4. Clean event handling
 * 5. Copy button functionality
 */
export class CodeBlockHandler extends BaseBlockHandler {
  type = 'code';

  private highlightTimer: any = null;
  private highlightJs: HLJSApi | null = null;
  
  render(block: IBlock, isSelected: boolean): string {
    const language = block.metadata?.language || 'typescript';
    const content = block.content || '';
    const lineCount = content.split('\n').length;
    
    // Generate line numbers
    let lineNumbersHtml = '';
    for (let i = 1; i <= lineCount; i++) {
      lineNumbersHtml += `<div class="line-number">${i}</div>`;
    }
    
    // Generate language options
    const languageOptions = PROGRAMMING_LANGUAGES.map(lang => {
      const value = lang.toLowerCase();
      return `<option value="${value}" ${value === language ? 'selected' : ''}>${lang}</option>`;
    }).join('');
    
    return `
      <div class="code-block-container${isSelected ? ' selected' : ''}" data-language="${language}">
        <div class="code-header">
          <select class="language-selector" data-block-id="${block.id}">
            ${languageOptions}
          </select>
          <button class="copy-button" title="Copy code">
            <svg class="copy-icon" width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
              <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z"></path>
              <path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z"></path>
            </svg>
            <span class="copy-text">Copy</span>
          </button>
        </div>
        <div class="code-body">
          <div class="line-numbers">${lineNumbersHtml}</div>
          <div class="code-content">
            <pre class="code-pre"><code class="code-editor" 
                 contenteditable="true"
                 data-block-id="${block.id}"
                 data-block-type="${block.type}"
                 spellcheck="false">${this.escapeHtml(content)}</code></pre>
          </div>
        </div>
      </div>
    `;
  }
  
  setup(element: HTMLElement, block: IBlock, handlers: IBlockEventHandlers): void {
    const editor = element.querySelector('.code-editor') as HTMLElement;
    const container = element.querySelector('.code-block-container') as HTMLElement;
    const copyButton = element.querySelector('.copy-button') as HTMLButtonElement;
    const languageSelector = element.querySelector('.language-selector') as HTMLSelectElement;
    
    if (!editor || !container) return;
    
    // Setup language selector
    if (languageSelector) {
      languageSelector.addEventListener('change', (e) => {
        const newLanguage = (e.target as HTMLSelectElement).value;
        block.metadata = { ...block.metadata, language: newLanguage };
        container.setAttribute('data-language', newLanguage);
        
        // Update the syntax highlighting if content exists and not focused
        if (block.content && document.activeElement !== editor) {
          this.applyHighlighting(element, block);
        }
        
        // Notify about the change
        if (handlers.onInput) {
          handlers.onInput(new InputEvent('input'));
        }
      });
    }
    
    // Setup copy button
    if (copyButton) {
      copyButton.addEventListener('click', async () => {
        const content = editor.textContent || '';
        
        try {
          await navigator.clipboard.writeText(content);
          
          // Show feedback
          const copyText = copyButton.querySelector('.copy-text') as HTMLElement;
          const originalText = copyText.textContent;
          copyText.textContent = 'Copied!';
          copyButton.classList.add('copied');
          
          // Reset after 2 seconds
          setTimeout(() => {
            copyText.textContent = originalText;
            copyButton.classList.remove('copied');
          }, 2000);
        } catch (err) {
          console.error('Failed to copy:', err);
          // Fallback for older browsers
          const textArea = document.createElement('textarea');
          textArea.value = content;
          textArea.style.position = 'fixed';
          textArea.style.opacity = '0';
          document.body.appendChild(textArea);
          textArea.select();
          try {
            // @ts-ignore - execCommand is deprecated but needed for fallback
            document.execCommand('copy');
            // Show feedback
            const copyText = copyButton.querySelector('.copy-text') as HTMLElement;
            const originalText = copyText.textContent;
            copyText.textContent = 'Copied!';
            copyButton.classList.add('copied');
            
            setTimeout(() => {
              copyText.textContent = originalText;
              copyButton.classList.remove('copied');
            }, 2000);
          } catch (err) {
            console.error('Fallback copy failed:', err);
          }
          document.body.removeChild(textArea);
        }
      });
    }
    
    // Track if we're currently editing
    let isEditing = false;
    
    // Focus handler
    editor.addEventListener('focus', () => {
      isEditing = true;
      container.classList.add('editing');
      
      // Remove all syntax highlighting when focused
      const content = editor.textContent || '';
      editor.textContent = content; // This removes all HTML formatting
      
      // Restore cursor position after removing highlighting
      requestAnimationFrame(() => {
        const range = document.createRange();
        const selection = window.getSelection();
        if (editor.firstChild) {
          range.setStart(editor.firstChild, 0);
          range.collapse(true);
          selection?.removeAllRanges();
          selection?.addRange(range);
        }
      });
      
      handlers.onFocus();
    });
    
    // Blur handler
    editor.addEventListener('blur', () => {
      isEditing = false;
      container.classList.remove('editing');
      // Apply final highlighting on blur
      this.applyHighlighting(element, block);
      handlers.onBlur();
    });
    
    // Input handler
    editor.addEventListener('input', (e) => {
      handlers.onInput(e as InputEvent);
      
      // Update line numbers
      this.updateLineNumbers(element);
      
      // Clear any pending highlight timer (no highlighting while editing)
      clearTimeout(this.highlightTimer);
    });
    
    // Keydown handler
    editor.addEventListener('keydown', (e) => {
      // Handle Tab key for code blocks
      if (e.key === 'Tab') {
        e.preventDefault();
        const selection = window.getSelection();
        if (selection && selection.rangeCount > 0) {
          const range = selection.getRangeAt(0);
          const textNode = document.createTextNode('  ');
          range.insertNode(textNode);
          range.setStartAfter(textNode);
          range.setEndAfter(textNode);
          selection.removeAllRanges();
          selection.addRange(range);
          handlers.onInput(new InputEvent('input'));
          this.updateLineNumbers(element);
        }
        return;
      }
      
      // Check cursor position for navigation keys
      if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key)) {
        const cursorPos = this.getCursorPosition(element);
        const textLength = editor.textContent?.length || 0;
        
        // For ArrowLeft at position 0 or ArrowRight at end, let parent handle navigation
        if ((e.key === 'ArrowLeft' && cursorPos === 0) || 
            (e.key === 'ArrowRight' && cursorPos === textLength)) {
          // Pass to parent handler for inter-block navigation
          handlers.onKeyDown(e);
          return;
        }
        
        // For ArrowUp/Down, check if we're at first/last line
        if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
          const lines = (editor.textContent || '').split('\n');
          const currentLine = this.getCurrentLineIndex(editor);
          
          if ((e.key === 'ArrowUp' && currentLine === 0) ||
              (e.key === 'ArrowDown' && currentLine === lines.length - 1)) {
            // Let parent handle navigation to prev/next block
            handlers.onKeyDown(e);
            return;
          }
        }
      }
      
      // Pass other keys to parent handler
      handlers.onKeyDown(e);
    });
    
    // Paste handler - plain text only
    editor.addEventListener('paste', (e) => {
      e.preventDefault();
      const text = e.clipboardData?.getData('text/plain');
      if (text) {
        const selection = window.getSelection();
        if (selection && selection.rangeCount > 0) {
          const range = selection.getRangeAt(0);
          range.deleteContents();
          const textNode = document.createTextNode(text);
          range.insertNode(textNode);
          range.setStartAfter(textNode);
          range.setEndAfter(textNode);
          selection.removeAllRanges();
          selection.addRange(range);
          handlers.onInput(new InputEvent('input'));
          this.updateLineNumbers(element);
        }
      }
    });
    
    // Composition handlers
    editor.addEventListener('compositionstart', () => handlers.onCompositionStart());
    editor.addEventListener('compositionend', () => handlers.onCompositionEnd());
    
    // Initial syntax highlighting if content exists and not focused
    if (block.content && document.activeElement !== editor) {
      requestAnimationFrame(() => {
        this.applyHighlighting(element, block);
      });
    }
  }
  
  private updateLineNumbers(element: HTMLElement): void {
    const editor = element.querySelector('.code-editor') as HTMLElement;
    const lineNumbersContainer = element.querySelector('.line-numbers') as HTMLElement;
    
    if (!editor || !lineNumbersContainer) return;
    
    const content = editor.textContent || '';
    const lines = content.split('\n');
    const lineCount = lines.length || 1;
    
    let lineNumbersHtml = '';
    for (let i = 1; i <= lineCount; i++) {
      lineNumbersHtml += `<div class="line-number">${i}</div>`;
    }
    
    lineNumbersContainer.innerHTML = lineNumbersHtml;
  }
  
  private getCurrentLineIndex(editor: HTMLElement): number {
    const selection = window.getSelection();
    if (!selection || selection.rangeCount === 0) return 0;
    
    const range = selection.getRangeAt(0);
    const preCaretRange = range.cloneRange();
    preCaretRange.selectNodeContents(editor);
    preCaretRange.setEnd(range.startContainer, range.startOffset);
    
    const textBeforeCursor = preCaretRange.toString();
    const linesBeforeCursor = textBeforeCursor.split('\n');
    
    return linesBeforeCursor.length - 1; // 0-indexed
  }
  
  private async applyHighlighting(element: HTMLElement, block: IBlock): Promise<void> {
    const editor = element.querySelector('.code-editor') as HTMLElement;
    if (!editor) return;

    // Load highlight.js from CDN if not already loaded
    if (!this.highlightJs) {
      this.highlightJs = await DeesServiceLibLoader.getInstance().loadHighlightJs();
    }

    // Store cursor position
    const cursorPos = this.getCursorPosition(element);

    // Get plain text content
    const content = editor.textContent || '';
    const language = block.metadata?.language || 'typescript';

    // Apply highlighting
    try {
      const result = this.highlightJs.highlight(content, {
        language: language,
        ignoreIllegals: true,
      });

      // Only update if we have valid highlighted content
      if (result.value) {
        editor.innerHTML = result.value;

        // Restore cursor position if editor is focused
        if (document.activeElement === editor && cursorPos !== null) {
          requestAnimationFrame(() => {
            WysiwygSelection.setCursorPosition(editor, cursorPos);
          });
        }
      }
    } catch (error) {
      // If highlighting fails, keep plain text
      console.warn('Syntax highlighting failed:', error);
    }
  }
  
  private escapeHtml(text: string): string {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
  }
  
  getContent(element: HTMLElement): string {
    const editor = element.querySelector('.code-editor') as HTMLElement;
    return editor?.textContent || '';
  }
  
  setContent(element: HTMLElement, content: string): void {
    const editor = element.querySelector('.code-editor') as HTMLElement;
    if (!editor) return;
    
    editor.textContent = content;
    this.updateLineNumbers(element);
    
    // Apply highlighting if not focused
    if (document.activeElement !== editor) {
      const block: IBlock = {
        id: editor.dataset.blockId || '',
        type: 'code',
        content: content,
        metadata: { 
          language: element.querySelector('.code-block-container')?.getAttribute('data-language') || 'typescript'
        }
      };
      this.applyHighlighting(element, block);
    }
  }
  
  getCursorPosition(element: HTMLElement): number | null {
    const editor = element.querySelector('.code-editor') as HTMLElement;
    if (!editor) return null;
    
    const selection = window.getSelection();
    if (!selection || selection.rangeCount === 0) return null;
    
    const range = selection.getRangeAt(0);
    if (!editor.contains(range.startContainer)) return null;
    
    const preCaretRange = document.createRange();
    preCaretRange.selectNodeContents(editor);
    preCaretRange.setEnd(range.startContainer, range.startOffset);
    
    return preCaretRange.toString().length;
  }
  
  setCursorToStart(element: HTMLElement): void {
    const editor = element.querySelector('.code-editor') as HTMLElement;
    if (editor) {
      WysiwygSelection.setCursorPosition(editor, 0);
    }
  }
  
  setCursorToEnd(element: HTMLElement): void {
    const editor = element.querySelector('.code-editor') as HTMLElement;
    if (editor) {
      const length = editor.textContent?.length || 0;
      WysiwygSelection.setCursorPosition(editor, length);
    }
  }
  
  focus(element: HTMLElement): void {
    const editor = element.querySelector('.code-editor') as HTMLElement;
    editor?.focus();
  }
  
  focusWithCursor(element: HTMLElement, position: 'start' | 'end' | number = 'end'): void {
    const editor = element.querySelector('.code-editor') as HTMLElement;
    if (!editor) return;
    
    editor.focus();
    
    requestAnimationFrame(() => {
      if (position === 'start') {
        this.setCursorToStart(element);
      } else if (position === 'end') {
        this.setCursorToEnd(element);
      } else if (typeof position === 'number') {
        WysiwygSelection.setCursorPosition(editor, position);
      }
    });
  }
  
  getSplitContent(element: HTMLElement): { before: string; after: string } | null {
    const position = this.getCursorPosition(element);
    if (position === null) return null;
    
    const content = this.getContent(element);
    return {
      before: content.substring(0, position),
      after: content.substring(position)
    };
  }
  
  getStyles(): string {
    return `
      /* Code Block Container - Minimalist shadcn style */
      .code-block-container {
        position: relative;
        margin: 12px 0;
        background: transparent;
        border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#374151')};
        border-radius: 6px;
        overflow: hidden;
        transition: all 0.15s ease;
      }
      
      .code-block-container.selected {
        border-color: ${cssManager.bdTheme('#9ca3af', '#6b7280')};
      }
      
      .code-block-container.editing {
        border-color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};
        background: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
      }
      
      /* Header - Simplified */
      .code-header {
        background: transparent;
        border-bottom: 1px solid ${cssManager.bdTheme('#e5e7eb', '#374151')};
        padding: 8px 12px;
        display: flex;
        justify-content: space-between;
        align-items: center;
      }
      
      .language-selector {
        font-size: 12px;
        color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};
        font-weight: 500;
        text-transform: uppercase;
        letter-spacing: 0.05em;
        font-family: ${cssGeistFontFamily};
        background: transparent;
        border: 1px solid transparent;
        border-radius: 4px;
        padding: 4px 8px;
        cursor: pointer;
        transition: all 0.15s ease;
        outline: none;
      }
      
      .language-selector:hover {
        background: ${cssManager.bdTheme('#f9fafb', '#1f2937')};
        border-color: ${cssManager.bdTheme('#e5e7eb', '#374151')};
        color: ${cssManager.bdTheme('#374151', '#e5e7eb')};
      }
      
      .language-selector:focus {
        border-color: ${cssManager.bdTheme('#9ca3af', '#6b7280')};
      }
      
      /* Copy Button - Minimal */
      .copy-button {
        display: flex;
        align-items: center;
        gap: 4px;
        padding: 4px 8px;
        background: transparent;
        border: 1px solid transparent;
        border-radius: 4px;
        color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};
        font-size: 12px;
        font-family: ${cssGeistFontFamily};
        cursor: pointer;
        transition: all 0.15s ease;
        outline: none;
      }
      
      .copy-button:hover {
        background: ${cssManager.bdTheme('#f9fafb', '#1f2937')};
        border-color: ${cssManager.bdTheme('#e5e7eb', '#374151')};
        color: ${cssManager.bdTheme('#374151', '#e5e7eb')};
      }
      
      .copy-button:active {
        transform: scale(0.98);
      }
      
      .copy-button.copied {
        color: ${cssManager.bdTheme('#059669', '#10b981')};
      }
      
      .copy-icon {
        flex-shrink: 0;
        opacity: 0.7;
      }
      
      .copy-button:hover .copy-icon {
        opacity: 1;
      }
      
      .copy-text {
        min-width: 40px;
        text-align: center;
      }
      
      /* Code Body */
      .code-body {
        display: flex;
        position: relative;
        background: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
      }
      
      /* Line Numbers - Subtle */
      .line-numbers {
        flex-shrink: 0;
        padding: 12px 0;
        background: transparent;
        text-align: right;
        user-select: none;
        min-width: 40px;
        border-right: 1px solid ${cssManager.bdTheme('#e5e7eb', '#374151')};
      }
      
      .line-number {
        padding: 0 12px 0 8px;
        color: ${cssManager.bdTheme('#9ca3af', '#4b5563')};
        font-family: ${cssMonoFontFamily};
        font-size: 13px;
        line-height: 20px;
        height: 20px;
      }
      
      /* Code Content */
      .code-content {
        flex: 1;
        overflow-x: auto;
        position: relative;
      }
      
      .code-pre {
        margin: 0;
        padding: 0;
        background: transparent;
      }
      
      .code-editor {
        display: block;
        padding: 12px 16px;
        margin: 0;
        font-family: ${cssMonoFontFamily};
        font-size: 13px;
        line-height: 20px;
        color: ${cssManager.bdTheme('#111827', '#f9fafb')};
        background: transparent;
        border: none;
        outline: none;
        white-space: pre-wrap;
        word-wrap: break-word;
        min-height: 60px;
        overflow: visible;
      }
      
      /* Placeholder */
      .code-editor:empty::before {
        content: "// Type or paste code here...";
        color: ${cssManager.bdTheme('#9ca3af', '#4b5563')};
        pointer-events: none;
      }
      
      /* When editing (focused), show grey text without highlighting */
      .code-block-container.editing .code-editor {
        color: ${cssManager.bdTheme('#6b7280', '#9ca3af')} !important;
      }
      
      .code-block-container.editing .code-editor * {
        color: inherit !important;
      }
      
      /* Syntax Highlighting - Muted colors */
      .code-editor .hljs-keyword {
        color: ${cssManager.bdTheme('#dc2626', '#f87171')};
        font-weight: 500;
      }
      
      .code-editor .hljs-string {
        color: ${cssManager.bdTheme('#059669', '#10b981')};
      }
      
      .code-editor .hljs-number {
        color: ${cssManager.bdTheme('#7c3aed', '#a78bfa')};
      }
      
      .code-editor .hljs-function {
        color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
      }
      
      .code-editor .hljs-comment {
        color: ${cssManager.bdTheme('#6b7280', '#6b7280')};
        font-style: italic;
      }
      
      .code-editor .hljs-variable,
      .code-editor .hljs-attr {
        color: ${cssManager.bdTheme('#ea580c', '#fb923c')};
      }
      
      .code-editor .hljs-class,
      .code-editor .hljs-title {
        color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
        font-weight: 500;
      }
      
      .code-editor .hljs-params {
        color: ${cssManager.bdTheme('#374151', '#e5e7eb')};
      }
      
      .code-editor .hljs-built_in {
        color: ${cssManager.bdTheme('#7c3aed', '#a78bfa')};
      }
      
      .code-editor .hljs-literal {
        color: ${cssManager.bdTheme('#7c3aed', '#a78bfa')};
      }
      
      .code-editor .hljs-meta {
        color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};
      }
      
      .code-editor .hljs-punctuation {
        color: ${cssManager.bdTheme('#374151', '#d1d5db')};
      }
      
      .code-editor .hljs-tag {
        color: ${cssManager.bdTheme('#dc2626', '#f87171')};
      }
      
      .code-editor .hljs-attribute {
        color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
      }
      
      .code-editor .hljs-selector-tag {
        color: ${cssManager.bdTheme('#dc2626', '#f87171')};
      }
      
      .code-editor .hljs-selector-class {
        color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
      }
      
      .code-editor .hljs-selector-id {
        color: ${cssManager.bdTheme('#7c3aed', '#a78bfa')};
      }
      
      /* Selection */
      .code-editor::selection,
      .code-editor *::selection {
        background: ${cssManager.bdTheme('rgba(99, 102, 241, 0.2)', 'rgba(99, 102, 241, 0.3)')};
      }
      
      /* Scrollbar styling - Minimal */
      .code-content::-webkit-scrollbar {
        height: 6px;
      }
      
      .code-content::-webkit-scrollbar-track {
        background: transparent;
      }
      
      .code-content::-webkit-scrollbar-thumb {
        background: ${cssManager.bdTheme('#d1d5db', '#4b5563')};
        border-radius: 3px;
      }
      
      .code-content::-webkit-scrollbar-thumb:hover {
        background: ${cssManager.bdTheme('#9ca3af', '#6b7280')};
      }
    `;
  }
}