import { html, type TemplateResult } from '@design.estate/dees-element';
import { type IBlock } from './wysiwyg.types.js';
import { WysiwygConverters } from './wysiwyg.converters.js';

export class WysiwygBlocks {
  static renderListContent(content: string, metadata?: any): string {
    const items = content.split('\n').filter(item => item.trim());
    if (items.length === 0) return '';
    const listTag = metadata?.listType === 'ordered' ? 'ol' : 'ul';
    // Don't escape HTML to preserve formatting
    return `<${listTag}>${items.map(item => `<li>${item}</li>`).join('')}</${listTag}>`;
  }

  static renderBlock(
    block: IBlock,
    isSelected: boolean,
    handlers: {
      onInput: (e: InputEvent) => void;
      onKeyDown: (e: KeyboardEvent) => void;
      onFocus: () => void;
      onBlur: () => void;
      onCompositionStart: () => void;
      onCompositionEnd: () => void;
      onMouseUp?: (e: MouseEvent) => void;
    }
  ): TemplateResult {
    if (block.type === 'divider') {
      return html`
        <div
          class="block divider"
          data-block-id="${block.id}"
        >
          <hr>
        </div>
      `;
    }

    if (block.type === 'list') {
      return html`
        <div
          class="block list ${isSelected ? 'selected' : ''}"
          data-block-id="${block.id}"
          contenteditable="true"
          @input="${handlers.onInput}"
          @keydown="${handlers.onKeyDown}"
          @focus="${handlers.onFocus}"
          @blur="${handlers.onBlur}"
          @compositionstart="${handlers.onCompositionStart}"
          @compositionend="${handlers.onCompositionEnd}"
          @mouseup="${(e: MouseEvent) => {
          console.log('Block mouseup event fired');
          if (handlers.onMouseUp) handlers.onMouseUp(e);
        }}"
          .innerHTML="${this.renderListContent(block.content, block.metadata)}"
        ></div>
      `;
    }
    
    // Special rendering for code blocks with language indicator
    if (block.type === 'code') {
      const language = block.metadata?.language || 'plain text';
      return html`
        <div class="code-block-container">
          <div class="code-language">${language}</div>
          <div
            class="block ${block.type} ${isSelected ? 'selected' : ''}"
            contenteditable="true"
            @input="${handlers.onInput}"
            @keydown="${handlers.onKeyDown}"
            @focus="${handlers.onFocus}"
            @blur="${handlers.onBlur}"
            @compositionstart="${handlers.onCompositionStart}"
            @compositionend="${handlers.onCompositionEnd}"
            @mouseup="${(e: MouseEvent) => {
              console.log('Block mouseup event fired');
              if (handlers.onMouseUp) handlers.onMouseUp(e);
            }}"
            .textContent="${block.content || ''}"
          ></div>
        </div>
      `;
    }
    
    const blockElement = html`
      <div
        class="block ${block.type} ${isSelected ? 'selected' : ''}"
        contenteditable="true"
        @input="${handlers.onInput}"
        @keydown="${handlers.onKeyDown}"
        @focus="${handlers.onFocus}"
        @blur="${handlers.onBlur}"
        @compositionstart="${handlers.onCompositionStart}"
        @compositionend="${handlers.onCompositionEnd}"
        @mouseup="${(e: MouseEvent) => {
          console.log('Block mouseup event fired');
          if (handlers.onMouseUp) handlers.onMouseUp(e);
        }}"
        .innerHTML="${block.content || ''}"
      ></div>
    `;
    
    return blockElement;
  }

  static setCursorToEnd(element: HTMLElement): void {
    const sel = window.getSelection();
    if (!sel) return;
    
    const range = document.createRange();
    
    // Handle different content types
    if (element.childNodes.length === 0) {
      // Empty element - add a zero-width space to enable cursor
      const textNode = document.createTextNode('\u200B');
      element.appendChild(textNode);
      range.setStart(textNode, 1);
      range.collapse(true);
    } else {
      // Find the last text node or element
      const lastNode = this.getLastNode(element);
      if (lastNode.nodeType === Node.TEXT_NODE) {
        range.setStart(lastNode, lastNode.textContent?.length || 0);
      } else {
        range.setStartAfter(lastNode);
      }
      range.collapse(true);
    }
    
    sel.removeAllRanges();
    sel.addRange(range);
    
    // Remove zero-width space if it was added
    if (element.textContent === '\u200B') {
      element.textContent = '';
    }
  }

  static setCursorToStart(element: HTMLElement): void {
    const sel = window.getSelection();
    if (!sel) return;
    
    const range = document.createRange();
    
    // Handle different content types
    if (element.childNodes.length === 0) {
      // Empty element
      range.setStart(element, 0);
      range.collapse(true);
    } else {
      // Find the first text node or element
      const firstNode = this.getFirstNode(element);
      if (firstNode.nodeType === Node.TEXT_NODE) {
        range.setStart(firstNode, 0);
      } else {
        range.setStartBefore(firstNode);
      }
      range.collapse(true);
    }
    
    sel.removeAllRanges();
    sel.addRange(range);
  }
  
  private static getLastNode(element: Node): Node {
    if (element.childNodes.length === 0) {
      return element;
    }
    
    const lastChild = element.childNodes[element.childNodes.length - 1];
    if (lastChild.nodeType === Node.TEXT_NODE || lastChild.childNodes.length === 0) {
      return lastChild;
    }
    
    return this.getLastNode(lastChild);
  }
  
  private static getFirstNode(element: Node): Node {
    if (element.childNodes.length === 0) {
      return element;
    }
    
    const firstChild = element.childNodes[0];
    if (firstChild.nodeType === Node.TEXT_NODE || firstChild.childNodes.length === 0) {
      return firstChild;
    }
    
    return this.getFirstNode(firstChild);
  }

  static focusListItem(listElement: HTMLElement): void {
    const firstLi = listElement.querySelector('li');
    if (firstLi) {
      firstLi.focus();
      const range = document.createRange();
      const sel = window.getSelection();
      range.selectNodeContents(firstLi);
      range.collapse(true);
      sel!.removeAllRanges();
      sel!.addRange(range);
    }
  }
}