import { type IBlock } from './wysiwyg.types.js';
import { type IWysiwygComponent } from './wysiwyg.interfaces.js';
import { WysiwygShortcuts } from './wysiwyg.shortcuts.js';
import { WysiwygBlocks } from './wysiwyg.blocks.js';
import { WysiwygBlockOperations } from './wysiwyg.blockoperations.js';
import { WysiwygModalManager } from './wysiwyg.modalmanager.js';

export class WysiwygInputHandler {
  private component: IWysiwygComponent;
  private saveTimeout: any = null;

  constructor(component: IWysiwygComponent) {
    this.component = component;
  }

  /**
   * Handles input events for blocks
   */
  handleBlockInput(e: InputEvent, block: IBlock): void {
    if (this.component.isComposing) return;
    
    const target = e.target as HTMLDivElement;
    const textContent = target.textContent || '';
    
    // Check for block type transformations BEFORE updating content
    const detectedType = this.detectBlockTypeIntent(textContent);
    if (detectedType && detectedType.type !== block.type) {
      e.preventDefault();
      this.handleBlockTransformation(block, detectedType, target);
      return;
    }
    
    // Handle slash commands
    this.handleSlashCommand(textContent, target);
    
    // Don't update block content immediately - let the block handle its own content
    // This prevents re-renders during typing
    
    // Schedule auto-save (which will sync content later)
    this.scheduleAutoSave();
  }

  /**
   * Updates block content based on its type
   */
  private updateBlockContent(block: IBlock, target: HTMLDivElement): void {
    // Get the block component for proper content extraction
    const wrapperElement = target.closest('.block-wrapper');
    const blockComponent = wrapperElement?.querySelector('dees-wysiwyg-block') as any;
    
    if (blockComponent) {
      // Use the block component's getContent method for consistency
      const newContent = blockComponent.getContent();
      // Only update if content actually changed to avoid unnecessary updates
      if (block.content !== newContent) {
        block.content = newContent;
      }
      
      // Update list metadata if needed
      if (block.type === 'list') {
        const listElement = target.querySelector('ol, ul');
        if (listElement) {
          block.metadata = { 
            listType: listElement.tagName.toLowerCase() === 'ol' ? 'ordered' : 'bullet' 
          };
        }
      }
    } else {
      // Fallback if block component not found
      if (block.type === 'list') {
        const listItems = target.querySelectorAll('li');
        // Use innerHTML to preserve formatting
        block.content = Array.from(listItems).map(li => li.innerHTML || '').join('\n');
        
        const listElement = target.querySelector('ol, ul');
        if (listElement) {
          block.metadata = { 
            listType: listElement.tagName.toLowerCase() === 'ol' ? 'ordered' : 'bullet' 
          };
        }
      } else if (block.type === 'code') {
        block.content = target.textContent || '';
      } else {
        block.content = target.innerHTML || '';
      }
    }
  }

  /**
   * Detects if the user is trying to create a specific block type
   */
  private detectBlockTypeIntent(content: string): { type: IBlock['type'], listType?: 'bullet' | 'ordered' } | null {
    // Check heading patterns
    const headingResult = WysiwygShortcuts.checkHeadingShortcut(content);
    if (headingResult) {
      return headingResult;
    }
    
    // Check list patterns
    const listResult = WysiwygShortcuts.checkListShortcut(content);
    if (listResult) {
      return listResult;
    }
    
    // Check quote pattern
    if (WysiwygShortcuts.checkQuoteShortcut(content)) {
      return { type: 'quote' };
    }
    
    // Check code pattern
    if (WysiwygShortcuts.checkCodeShortcut(content)) {
      return { type: 'code' };
    }
    
    // Check divider pattern
    if (WysiwygShortcuts.checkDividerShortcut(content)) {
      return { type: 'divider' };
    }
    
    return null;
  }

  /**
   * Handles block type transformation
   */
  private async handleBlockTransformation(
    block: IBlock, 
    detectedType: { type: IBlock['type'], listType?: 'bullet' | 'ordered' }, 
    target: HTMLDivElement
  ): Promise<void> {
    const blockOps = this.component.blockOperations;
    
    if (detectedType.type === 'list') {
      block.type = 'list';
      block.content = '';
      block.metadata = { listType: detectedType.listType };
      
      const listTag = detectedType.listType === 'ordered' ? 'ol' : 'ul';
      target.innerHTML = `<${listTag}><li></li></${listTag}>`;
      
      this.component.updateValue();
      
      // Update the block element programmatically
      if (this.component.editorContentRef) {
        this.component.updateBlockElement(block.id);
      }
      
      setTimeout(() => {
        WysiwygBlocks.focusListItem(target);
      }, 0);
    } else if (detectedType.type === 'divider') {
      block.type = 'divider';
      block.content = ' ';
      
      // Update the block element programmatically
      if (this.component.editorContentRef) {
        this.component.updateBlockElement(block.id);
      }
      
      const newBlock = blockOps.createBlock();
      blockOps.insertBlockAfter(block, newBlock);
      
      this.component.updateValue();
    } else if (detectedType.type === 'code') {
      const language = await WysiwygModalManager.showLanguageSelectionModal();
      if (language) {
        block.type = 'code';
        block.content = '';
        block.metadata = { language };
        target.textContent = '';
        
        this.component.updateValue();
        
        // Update the block element programmatically
        if (this.component.editorContentRef) {
          this.component.updateBlockElement(block.id);
        }
        
        // Focus the code block
        setTimeout(async () => {
          await blockOps.focusBlock(block.id, 'start');
        }, 50);
      }
    } else {
      block.type = detectedType.type;
      block.content = '';
      target.textContent = '';
      
      this.component.updateValue();
      
      // Update the block element programmatically
      if (this.component.editorContentRef) {
        this.component.updateBlockElement(block.id);
      }
      
      // Focus the transformed block
      setTimeout(async () => {
        await blockOps.focusBlock(block.id, 'start');
      }, 50);
    }
  }

  /**
   * Handles slash command detection and menu display
   */
  private handleSlashCommand(textContent: string, target: HTMLDivElement): void {
    const slashMenu = this.component.slashMenu;
    const isSlashMenuVisible = slashMenu && slashMenu.visible;
    
    if (textContent === '/' || (textContent.startsWith('/') && isSlashMenuVisible)) {
      if (!isSlashMenuVisible && textContent === '/') {
        // Get position for menu based on cursor location
        const rect = this.getCaretCoordinates(target);
        
        // Show the slash menu at the cursor position
        slashMenu.show(
          { x: rect.left, y: rect.bottom + 4 },
          (type: string) => {
            this.component.insertBlock(type);
          }
        );
        
        // Ensure the block maintains focus
        requestAnimationFrame(() => {
          if (document.activeElement !== target) {
            target.focus();
          }
        });
      }
      // Update filter
      if (slashMenu) {
        slashMenu.updateFilter(textContent.slice(1));
      }
    } else if (!textContent.startsWith('/')) {
      this.component.closeSlashMenu();
    }
  }
  
  /**
   * Gets the coordinates of the caret/cursor
   */
  private getCaretCoordinates(element: HTMLElement): DOMRect {
    const selection = window.getSelection();
    if (selection && selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      const rect = range.getBoundingClientRect();
      if (rect.width > 0 || rect.height > 0) {
        return rect;
      }
    }
    
    // Fallback to element position
    return element.getBoundingClientRect();
  }

  /**
   * Schedules auto-save after a delay
   */
  private scheduleAutoSave(): void {
    if (this.saveTimeout) {
      clearTimeout(this.saveTimeout);
    }
    // Don't auto-save if slash menu is open
    if (this.component.slashMenu && this.component.slashMenu.visible) {
      return;
    }
    this.saveTimeout = setTimeout(() => {
      // Sync all block content from DOM before saving
      this.syncAllBlockContent();
      // Only update value, don't trigger any re-renders
      this.component.updateValue();
      // Don't call requestUpdate() as it's not needed
    }, 2000); // Increased delay to reduce interference with typing
  }
  
  /**
   * Syncs content from all block DOMs to the data model
   */
  private syncAllBlockContent(): void {
    this.component.blocks.forEach((block: IBlock) => {
      const wrapperElement = this.component.shadowRoot?.querySelector(`[data-block-id="${block.id}"]`);
      const blockComponent = wrapperElement?.querySelector('dees-wysiwyg-block') as any;
      
      if (blockComponent && blockComponent.getContent) {
        const newContent = blockComponent.getContent();
        // Only update if content actually changed
        if (block.content !== newContent) {
          block.content = newContent;
        }
      }
    });
  }

  /**
   * Cleans up resources
   */
  destroy(): void {
    if (this.saveTimeout) {
      clearTimeout(this.saveTimeout);
    }
  }
}