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 QuoteBlockHandler extends BaseBlockHandler {
  type = 'quote';
  
  // Track cursor position
  private lastKnownCursorPosition: number = 0;
  private lastSelectedText: string = '';
  private selectionHandler: (() => void) | null = null;
  
  render(block: IBlock, isSelected: boolean): string {
    const selectedClass = isSelected ? ' selected' : '';
    const placeholder = this.getPlaceholder();
    
    
    return `
      <div
        class="block quote${selectedClass}"
        contenteditable="true"
        data-placeholder="${placeholder}"
        data-block-id="${block.id}"
        data-block-type="${block.type}"
      ></div>
    `;
  }
  
  setup(element: HTMLElement, block: IBlock, handlers: IBlockEventHandlers): void {
    const quoteBlock = element.querySelector('.block.quote') as HTMLDivElement;
    if (!quoteBlock) {
      console.error('QuoteBlockHandler.setup: No quote block element found');
      return;
    }
    
    // Set initial content if needed
    if (block.content && !quoteBlock.innerHTML) {
      quoteBlock.innerHTML = block.content;
    }
    
    // Input handler with cursor tracking
    quoteBlock.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 with cursor tracking
    quoteBlock.addEventListener('keydown', (e) => {
      // Track cursor position before keydown
      const pos = this.getCursorPosition(element);
      if (pos !== null) {
        this.lastKnownCursorPosition = pos;
      }
      
      handlers.onKeyDown(e);
    });
    
    // Focus handler
    quoteBlock.addEventListener('focus', () => {
      handlers.onFocus();
    });
    
    // Blur handler
    quoteBlock.addEventListener('blur', () => {
      handlers.onBlur();
    });
    
    // Composition handlers for IME support
    quoteBlock.addEventListener('compositionstart', () => {
      handlers.onCompositionStart();
    });
    
    quoteBlock.addEventListener('compositionend', () => {
      handlers.onCompositionEnd();
    });
    
    // Mouse up handler
    quoteBlock.addEventListener('mouseup', (e) => {
      const pos = this.getCursorPosition(element);
      if (pos !== null) {
        this.lastKnownCursorPosition = pos;
      }
      
      // Selection will be handled by selectionchange event
      handlers.onMouseUp?.(e);
    });
    
    // Click handler with delayed cursor tracking
    quoteBlock.addEventListener('click', (e: MouseEvent) => {
      // Small delay to let browser set cursor position
      setTimeout(() => {
        const pos = this.getCursorPosition(element);
        if (pos !== null) {
          this.lastKnownCursorPosition = pos;
        }
      }, 0);
    });
    
    // Keyup handler for additional cursor tracking
    quoteBlock.addEventListener('keyup', (e) => {
      const pos = this.getCursorPosition(element);
      if (pos !== null) {
        this.lastKnownCursorPosition = pos;
      }
    });
    
    // Set up selection change handler
    this.setupSelectionHandler(element, quoteBlock, block);
  }
  
  private setupSelectionHandler(element: HTMLElement, quoteBlock: HTMLDivElement, block: IBlock): void {
    // Add selection change handler
    const checkSelection = () => {
      const selection = window.getSelection();
      if (!selection || selection.rangeCount === 0) return;
      
      const selectedText = selection.toString();
      if (selectedText.length === 0) {
        // Clear selection if no text
        if (this.lastSelectedText) {
          this.lastSelectedText = '';
          this.dispatchSelectionEvent(element, {
            text: '',
            blockId: block.id,
            hasSelection: false
          });
        }
        return;
      }
      
      // Get parent wysiwyg component's shadow root - traverse from shadow root
      const wysiwygBlock = (quoteBlock.getRootNode() as ShadowRoot).host as any;
      const parentComponent = wysiwygBlock?.closest('dees-input-wysiwyg');
      const parentShadowRoot = parentComponent?.shadowRoot;
      const blockShadowRoot = wysiwygBlock?.shadowRoot;
      
      // Use getComposedRanges with shadow roots as per MDN docs
      const shadowRoots: ShadowRoot[] = [];
      if (parentShadowRoot) shadowRoots.push(parentShadowRoot);
      if (blockShadowRoot) shadowRoots.push(blockShadowRoot);
      
      // Get selection info using our Shadow DOM-aware utility
      const selectionInfo = WysiwygSelection.getSelectionInfo(...shadowRoots);
      if (!selectionInfo) return;
      
      // Check if selection is within this block
      const startInBlock = WysiwygSelection.containsAcrossShadowDOM(quoteBlock, selectionInfo.startContainer);
      const endInBlock = WysiwygSelection.containsAcrossShadowDOM(quoteBlock, selectionInfo.endContainer);
      
      if (startInBlock || endInBlock) {
        if (selectedText !== this.lastSelectedText) {
          this.lastSelectedText = selectedText;
          
          // Create range and get rect
          const range = WysiwygSelection.createRangeFromInfo(selectionInfo);
          const rect = range.getBoundingClientRect();
          
          // Dispatch event
          this.dispatchSelectionEvent(element, {
            text: selectedText.trim(),
            blockId: block.id,
            range: range,
            rect: rect,
            hasSelection: true
          });
        }
      } else if (this.lastSelectedText) {
        // Clear selection if no longer in this block
        this.lastSelectedText = '';
        this.dispatchSelectionEvent(element, {
          text: '',
          blockId: block.id,
          hasSelection: false
        });
      }
    };
    
    // Listen for selection changes
    document.addEventListener('selectionchange', checkSelection);
    
    // Store the handler for cleanup
    this.selectionHandler = checkSelection;
    
    // Clean up on disconnect (will be called by dees-wysiwyg-block)
    const wysiwygBlock = (quoteBlock.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 `
      /* Quote specific styles */
      .block.quote {
        border-left: 3px solid ${cssManager.bdTheme('#0066cc', '#4d94ff')};
        padding-left: 20px;
        color: ${cssManager.bdTheme('#555', '#b0b0b0')};
        font-style: italic;
        line-height: 1.6;
        margin: 16px 0;
      }
    `;
  }
  
  getPlaceholder(): string {
    return 'Add a quote...';
  }
  
  // Helper methods for quote functionality
  
  getCursorPosition(element: HTMLElement, context?: any): number | null {
    // Get the actual quote element
    const quoteBlock = element.querySelector('.block.quote') as HTMLDivElement;
    if (!quoteBlock) {
      return null;
    }
    
    // Get shadow roots from context
    const wysiwygBlock = context?.component;
    const parentComponent = wysiwygBlock?.closest('dees-input-wysiwyg');
    const parentShadowRoot = parentComponent?.shadowRoot;
    const blockShadowRoot = context?.shadowRoot;
    
    // Get selection info with both shadow roots for proper traversal
    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(quoteBlock, selectionInfo.startContainer)) {
      return null;
    }
    
    // Create a range from start of element to cursor position
    const preCaretRange = document.createRange();
    preCaretRange.selectNodeContents(quoteBlock);
    preCaretRange.setEnd(selectionInfo.startContainer, selectionInfo.startOffset);
    
    // Get the text content length up to cursor
    const position = preCaretRange.toString().length;
    
    return position;
  }
  
  getContent(element: HTMLElement, context?: any): string {
    const quoteBlock = element.querySelector('.block.quote') as HTMLDivElement;
    if (!quoteBlock) return '';
    
    // For quotes, get the innerHTML which includes formatting tags
    const content = quoteBlock.innerHTML || '';
    return content;
  }
  
  setContent(element: HTMLElement, content: string, context?: any): void {
    const quoteBlock = element.querySelector('.block.quote') as HTMLDivElement;
    if (!quoteBlock) return;
    
    // Store if we have focus
    const hadFocus = document.activeElement === quoteBlock || 
                     element.shadowRoot?.activeElement === quoteBlock;
    
    quoteBlock.innerHTML = content;
    
    // Restore focus if we had it
    if (hadFocus) {
      quoteBlock.focus();
    }
  }
  
  setCursorToStart(element: HTMLElement, context?: any): void {
    const quoteBlock = element.querySelector('.block.quote') as HTMLDivElement;
    if (quoteBlock) {
      WysiwygBlocks.setCursorToStart(quoteBlock);
    }
  }
  
  setCursorToEnd(element: HTMLElement, context?: any): void {
    const quoteBlock = element.querySelector('.block.quote') as HTMLDivElement;
    if (quoteBlock) {
      WysiwygBlocks.setCursorToEnd(quoteBlock);
    }
  }
  
  focus(element: HTMLElement, context?: any): void {
    const quoteBlock = element.querySelector('.block.quote') as HTMLDivElement;
    if (!quoteBlock) return;
    
    // Ensure the element is focusable
    if (!quoteBlock.hasAttribute('contenteditable')) {
      quoteBlock.setAttribute('contenteditable', 'true');
    }
    
    quoteBlock.focus();
    
    // If focus failed, try again after a microtask
    if (document.activeElement !== quoteBlock && element.shadowRoot?.activeElement !== quoteBlock) {
      Promise.resolve().then(() => {
        quoteBlock.focus();
      });
    }
  }
  
  focusWithCursor(element: HTMLElement, position: 'start' | 'end' | number = 'end', context?: any): void {
    const quoteBlock = element.querySelector('.block.quote') as HTMLDivElement;
    if (!quoteBlock) return;
    
    // Ensure element is focusable first
    if (!quoteBlock.hasAttribute('contenteditable')) {
      quoteBlock.setAttribute('contenteditable', 'true');
    }
    
    // Focus the element
    quoteBlock.focus();
    
    // Set cursor position after focus is established
    const setCursor = () => {
      if (position === 'start') {
        this.setCursorToStart(element, context);
      } else if (position === 'end') {
        this.setCursorToEnd(element, context);
      } else if (typeof position === 'number') {
        // Use the selection utility to set cursor position
        WysiwygSelection.setCursorPosition(quoteBlock, position);
      }
    };
    
    // Ensure cursor is set after focus
    if (document.activeElement === quoteBlock || element.shadowRoot?.activeElement === quoteBlock) {
      setCursor();
    } else {
      // Wait for focus to be established
      Promise.resolve().then(() => {
        if (document.activeElement === quoteBlock || element.shadowRoot?.activeElement === quoteBlock) {
          setCursor();
        }
      });
    }
  }
  
  getSplitContent(element: HTMLElement, context?: any): { before: string; after: string } | null {
    const quoteBlock = element.querySelector('.block.quote') as HTMLDivElement;
    if (!quoteBlock) {
      return null;
    }
    
    // Get shadow roots from context
    const wysiwygBlock = context?.component;
    const parentComponent = wysiwygBlock?.closest('dees-input-wysiwyg');
    const parentShadowRoot = parentComponent?.shadowRoot;
    const blockShadowRoot = context?.shadowRoot;
    
    // Get selection info with both shadow roots for proper traversal
    const shadowRoots: ShadowRoot[] = [];
    if (parentShadowRoot) shadowRoots.push(parentShadowRoot);
    if (blockShadowRoot) shadowRoots.push(blockShadowRoot);
    
    const selectionInfo = WysiwygSelection.getSelectionInfo(...shadowRoots);
    
    if (!selectionInfo) {
      // Try using last known cursor position
      if (this.lastKnownCursorPosition !== null) {
        const fullText = quoteBlock.textContent || '';
        const pos = Math.min(this.lastKnownCursorPosition, fullText.length);
        return {
          before: fullText.substring(0, pos),
          after: fullText.substring(pos)
        };
      }
      return null;
    }
    
    // Make sure the selection is within this block
    if (!WysiwygSelection.containsAcrossShadowDOM(quoteBlock, selectionInfo.startContainer)) {
      // Try using last known cursor position
      if (this.lastKnownCursorPosition !== null) {
        const fullText = quoteBlock.textContent || '';
        const pos = Math.min(this.lastKnownCursorPosition, fullText.length);
        return {
          before: fullText.substring(0, pos),
          after: fullText.substring(pos)
        };
      }
      return null;
    }
    
    // Get cursor position first
    const cursorPos = this.getCursorPosition(element, context);
    
    if (cursorPos === null || cursorPos === 0) {
      // If cursor is at start or can't determine position, move all content
      return {
        before: '',
        after: quoteBlock.innerHTML
      };
    }
    
    // For HTML content, split using ranges to preserve formatting
    const beforeRange = document.createRange();
    const afterRange = document.createRange();
    
    // Before range: from start of element to cursor
    beforeRange.setStart(quoteBlock, 0);
    beforeRange.setEnd(selectionInfo.startContainer, selectionInfo.startOffset);
    
    // After range: from cursor to end of element
    afterRange.setStart(selectionInfo.startContainer, selectionInfo.startOffset);
    afterRange.setEnd(quoteBlock, quoteBlock.childNodes.length);
    
    // Extract HTML content
    const beforeFragment = beforeRange.cloneContents();
    const afterFragment = afterRange.cloneContents();
    
    // Convert to HTML strings
    const tempDiv = document.createElement('div');
    tempDiv.appendChild(beforeFragment);
    const beforeHtml = tempDiv.innerHTML;
    
    tempDiv.innerHTML = '';
    tempDiv.appendChild(afterFragment);
    const afterHtml = tempDiv.innerHTML;
    
    return { 
      before: beforeHtml, 
      after: afterHtml 
    };
  }
}