import { BaseBlockHandler, type IBlockEventHandlers } from '../block.base.js';
import type { IBlock } from '../../wysiwyg.types.js';
import { cssManager } from '@design.estate/dees-element';
import { WysiwygBlocks } from '../../wysiwyg.blocks.js';
import { WysiwygSelection } from '../../wysiwyg.selection.js';

export class ListBlockHandler extends BaseBlockHandler {
  type = 'list';
  
  // Track cursor position and list state
  private lastKnownCursorPosition: number = 0;
  private lastSelectedText: string = '';
  private selectionHandler: (() => void) | null = null;
  
  render(block: IBlock, isSelected: boolean): string {
    const selectedClass = isSelected ? ' selected' : '';
    const listType = block.metadata?.listType || 'unordered';
    const listTag = listType === 'ordered' ? 'ol' : 'ul';
    
    // Render list content
    const listContent = this.renderListContent(block.content, block.metadata);
    
    return `
      <div
        class="block list${selectedClass}"
        contenteditable="true"
        data-block-id="${block.id}"
        data-block-type="${block.type}"
      >${listContent}</div>
    `;
  }
  
  private renderListContent(content: string | undefined, metadata: any): string {
    if (!content) return '<ul><li></li></ul>';
    
    const listType = metadata?.listType || 'unordered';
    const listTag = listType === 'ordered' ? 'ol' : 'ul';
    
    // Split content by newlines to create list items
    const lines = content.split('\n').filter(line => line.trim());
    if (lines.length === 0) {
      return `<${listTag}><li></li></${listTag}>`;
    }
    
    const listItems = lines.map(line => `<li>${line}</li>`).join('');
    return `<${listTag}>${listItems}</${listTag}>`;
  }
  
  setup(element: HTMLElement, block: IBlock, handlers: IBlockEventHandlers): void {
    const listBlock = element.querySelector('.block.list') as HTMLDivElement;
    if (!listBlock) {
      console.error('ListBlockHandler.setup: No list block element found');
      return;
    }
    
    // Set initial content if needed
    if (block.content && !listBlock.innerHTML) {
      listBlock.innerHTML = this.renderListContent(block.content, block.metadata);
    }
    
    // Input handler
    listBlock.addEventListener('input', (e) => {
      handlers.onInput(e as InputEvent);
      
      // Track cursor position after input
      const pos = this.getCursorPosition(element);
      if (pos !== null) {
        this.lastKnownCursorPosition = pos;
      }
    });
    
    // Keydown handler
    listBlock.addEventListener('keydown', (e) => {
      // Track cursor position before keydown
      const pos = this.getCursorPosition(element);
      if (pos !== null) {
        this.lastKnownCursorPosition = pos;
      }
      
      // Special handling for Enter key in lists
      if (e.key === 'Enter' && !e.shiftKey) {
        const selection = window.getSelection();
        if (selection && selection.rangeCount > 0) {
          const range = selection.getRangeAt(0);
          const currentLi = range.startContainer.parentElement?.closest('li');
          
          if (currentLi && currentLi.textContent === '') {
            // Empty list item - exit list mode
            e.preventDefault();
            handlers.onKeyDown(e);
            return;
          }
          // Otherwise, let browser create new list item naturally
        }
      }
      
      handlers.onKeyDown(e);
    });
    
    // Focus handler
    listBlock.addEventListener('focus', () => {
      handlers.onFocus();
    });
    
    // Blur handler
    listBlock.addEventListener('blur', () => {
      handlers.onBlur();
    });
    
    // Composition handlers for IME support
    listBlock.addEventListener('compositionstart', () => {
      handlers.onCompositionStart();
    });
    
    listBlock.addEventListener('compositionend', () => {
      handlers.onCompositionEnd();
    });
    
    // Mouse up handler
    listBlock.addEventListener('mouseup', (e) => {
      const pos = this.getCursorPosition(element);
      if (pos !== null) {
        this.lastKnownCursorPosition = pos;
      }
      handlers.onMouseUp?.(e);
    });
    
    // Click handler
    listBlock.addEventListener('click', (e: MouseEvent) => {
      setTimeout(() => {
        const pos = this.getCursorPosition(element);
        if (pos !== null) {
          this.lastKnownCursorPosition = pos;
        }
      }, 0);
    });
    
    // Keyup handler
    listBlock.addEventListener('keyup', (e) => {
      const pos = this.getCursorPosition(element);
      if (pos !== null) {
        this.lastKnownCursorPosition = pos;
      }
    });
    
    // Set up selection handler
    this.setupSelectionHandler(element, listBlock, block);
  }
  
  private setupSelectionHandler(element: HTMLElement, listBlock: HTMLDivElement, block: IBlock): void {
    const checkSelection = () => {
      const selection = window.getSelection();
      if (!selection || selection.rangeCount === 0) return;
      
      const selectedText = selection.toString();
      if (selectedText.length === 0) {
        if (this.lastSelectedText) {
          this.lastSelectedText = '';
          this.dispatchSelectionEvent(element, {
            text: '',
            blockId: block.id,
            hasSelection: false
          });
        }
        return;
      }
      
      // Get parent wysiwyg component's shadow root
      const wysiwygBlock = (listBlock.getRootNode() as ShadowRoot).host as any;
      const parentComponent = wysiwygBlock?.closest('dees-input-wysiwyg');
      const parentShadowRoot = parentComponent?.shadowRoot;
      const blockShadowRoot = wysiwygBlock?.shadowRoot;
      
      const shadowRoots: ShadowRoot[] = [];
      if (parentShadowRoot) shadowRoots.push(parentShadowRoot);
      if (blockShadowRoot) shadowRoots.push(blockShadowRoot);
      
      const selectionInfo = WysiwygSelection.getSelectionInfo(...shadowRoots);
      if (!selectionInfo) return;
      
      const startInBlock = WysiwygSelection.containsAcrossShadowDOM(listBlock, selectionInfo.startContainer);
      const endInBlock = WysiwygSelection.containsAcrossShadowDOM(listBlock, selectionInfo.endContainer);
      
      if (startInBlock || endInBlock) {
        if (selectedText !== this.lastSelectedText) {
          this.lastSelectedText = selectedText;
          
          const range = WysiwygSelection.createRangeFromInfo(selectionInfo);
          const rect = range.getBoundingClientRect();
          
          this.dispatchSelectionEvent(element, {
            text: selectedText.trim(),
            blockId: block.id,
            range: range,
            rect: rect,
            hasSelection: true
          });
        }
      } else if (this.lastSelectedText) {
        this.lastSelectedText = '';
        this.dispatchSelectionEvent(element, {
          text: '',
          blockId: block.id,
          hasSelection: false
        });
      }
    };
    
    document.addEventListener('selectionchange', checkSelection);
    this.selectionHandler = checkSelection;
    
    // Cleanup on disconnect
    const wysiwygBlock = (listBlock.getRootNode() as ShadowRoot).host as any;
    if (wysiwygBlock) {
      const originalDisconnectedCallback = (wysiwygBlock as any).disconnectedCallback;
      (wysiwygBlock as any).disconnectedCallback = async function() {
        if (this.selectionHandler) {
          document.removeEventListener('selectionchange', this.selectionHandler);
          this.selectionHandler = null;
        }
        if (originalDisconnectedCallback) {
          await originalDisconnectedCallback.call(wysiwygBlock);
        }
      }.bind(this);
    }
  }
  
  private dispatchSelectionEvent(element: HTMLElement, detail: any): void {
    const event = new CustomEvent('block-text-selected', {
      detail,
      bubbles: true,
      composed: true
    });
    element.dispatchEvent(event);
  }
  
  getStyles(): string {
    return `
      /* List specific styles */
      .block.list {
        padding: 0;
      }
      
      .block.list ul,
      .block.list ol {
        margin: 0;
        padding-left: 24px;
      }
      
      .block.list li {
        margin: 4px 0;
        line-height: 1.6;
      }
      
      .block.list li:last-child {
        margin-bottom: 0;
      }
    `;
  }
  
  getPlaceholder(): string {
    return '';
  }
  
  // Helper methods for list functionality
  
  getCursorPosition(element: HTMLElement, context?: any): number | null {
    const listBlock = element.querySelector('.block.list') as HTMLDivElement;
    if (!listBlock) return null;
    
    const wysiwygBlock = context?.component;
    const parentComponent = wysiwygBlock?.closest('dees-input-wysiwyg');
    const parentShadowRoot = parentComponent?.shadowRoot;
    const blockShadowRoot = context?.shadowRoot;
    
    const shadowRoots: ShadowRoot[] = [];
    if (parentShadowRoot) shadowRoots.push(parentShadowRoot);
    if (blockShadowRoot) shadowRoots.push(blockShadowRoot);
    
    const selectionInfo = WysiwygSelection.getSelectionInfo(...shadowRoots);
    if (!selectionInfo) return null;
    
    if (!WysiwygSelection.containsAcrossShadowDOM(listBlock, selectionInfo.startContainer)) {
      return null;
    }
    
    // For lists, calculate position based on text content
    const preCaretRange = document.createRange();
    preCaretRange.selectNodeContents(listBlock);
    preCaretRange.setEnd(selectionInfo.startContainer, selectionInfo.startOffset);
    
    return preCaretRange.toString().length;
  }
  
  getContent(element: HTMLElement, context?: any): string {
    const listBlock = element.querySelector('.block.list') as HTMLDivElement;
    if (!listBlock) return '';
    
    // Extract text content from list items
    const listItems = listBlock.querySelectorAll('li');
    const content = Array.from(listItems)
      .map(li => li.textContent || '')
      .join('\n');
    
    return content;
  }
  
  setContent(element: HTMLElement, content: string, context?: any): void {
    const listBlock = element.querySelector('.block.list') as HTMLDivElement;
    if (!listBlock) return;
    
    const hadFocus = document.activeElement === listBlock || 
                     element.shadowRoot?.activeElement === listBlock;
    
    // Get current metadata to preserve list type
    const listElement = listBlock.querySelector('ul, ol');
    const isOrdered = listElement?.tagName === 'OL';
    
    // Update content
    listBlock.innerHTML = this.renderListContent(content, { listType: isOrdered ? 'ordered' : 'unordered' });
    
    if (hadFocus) {
      listBlock.focus();
    }
  }
  
  setCursorToStart(element: HTMLElement, context?: any): void {
    const listBlock = element.querySelector('.block.list') as HTMLDivElement;
    if (!listBlock) return;
    
    const firstLi = listBlock.querySelector('li');
    if (firstLi) {
      const textNode = this.getFirstTextNode(firstLi);
      if (textNode) {
        const range = document.createRange();
        const selection = window.getSelection();
        range.setStart(textNode, 0);
        range.setEnd(textNode, 0);
        selection?.removeAllRanges();
        selection?.addRange(range);
      }
    }
  }
  
  setCursorToEnd(element: HTMLElement, context?: any): void {
    const listBlock = element.querySelector('.block.list') as HTMLDivElement;
    if (!listBlock) return;
    
    const lastLi = listBlock.querySelector('li:last-child');
    if (lastLi) {
      const textNode = this.getLastTextNode(lastLi);
      if (textNode) {
        const range = document.createRange();
        const selection = window.getSelection();
        const textLength = textNode.textContent?.length || 0;
        range.setStart(textNode, textLength);
        range.setEnd(textNode, textLength);
        selection?.removeAllRanges();
        selection?.addRange(range);
      }
    }
  }
  
  private getFirstTextNode(element: Node): Text | null {
    if (element.nodeType === Node.TEXT_NODE) {
      return element as Text;
    }
    
    for (let i = 0; i < element.childNodes.length; i++) {
      const firstText = this.getFirstTextNode(element.childNodes[i]);
      if (firstText) return firstText;
    }
    
    return null;
  }
  
  private getLastTextNode(element: Node): Text | null {
    if (element.nodeType === Node.TEXT_NODE) {
      return element as Text;
    }
    
    for (let i = element.childNodes.length - 1; i >= 0; i--) {
      const lastText = this.getLastTextNode(element.childNodes[i]);
      if (lastText) return lastText;
    }
    
    return null;
  }
  
  focus(element: HTMLElement, context?: any): void {
    const listBlock = element.querySelector('.block.list') as HTMLDivElement;
    if (!listBlock) return;
    
    if (!listBlock.hasAttribute('contenteditable')) {
      listBlock.setAttribute('contenteditable', 'true');
    }
    
    listBlock.focus();
    
    if (document.activeElement !== listBlock && element.shadowRoot?.activeElement !== listBlock) {
      Promise.resolve().then(() => {
        listBlock.focus();
      });
    }
  }
  
  focusWithCursor(element: HTMLElement, position: 'start' | 'end' | number = 'end', context?: any): void {
    const listBlock = element.querySelector('.block.list') as HTMLDivElement;
    if (!listBlock) return;
    
    if (!listBlock.hasAttribute('contenteditable')) {
      listBlock.setAttribute('contenteditable', 'true');
    }
    
    listBlock.focus();
    
    const setCursor = () => {
      if (position === 'start') {
        this.setCursorToStart(element, context);
      } else if (position === 'end') {
        this.setCursorToEnd(element, context);
      } else if (typeof position === 'number') {
        // For numeric positions in lists, we need custom logic
        // This is complex due to list structure, so default to end
        this.setCursorToEnd(element, context);
      }
    };
    
    if (document.activeElement === listBlock || element.shadowRoot?.activeElement === listBlock) {
      setCursor();
    } else {
      Promise.resolve().then(() => {
        if (document.activeElement === listBlock || element.shadowRoot?.activeElement === listBlock) {
          setCursor();
        }
      });
    }
  }
  
  getSplitContent(element: HTMLElement, context?: any): { before: string; after: string } | null {
    const listBlock = element.querySelector('.block.list') as HTMLDivElement;
    if (!listBlock) return null;
    
    // For lists, we don't split content - instead let the keyboard handler
    // create a new paragraph block when Enter is pressed on empty list item
    return null;
  }
}