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';

export class WysiwygBlockOperations {
  private component: IWysiwygComponent;

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

  /**
   * Creates a new block with the specified parameters
   */
  createBlock(type: IBlock['type'] = 'paragraph', content: string = '', metadata?: any): IBlock {
    return {
      id: WysiwygShortcuts.generateBlockId(),
      type,
      content,
      ...(metadata && { metadata })
    };
  }

  /**
   * Inserts a block after the specified block
   */
  async insertBlockAfter(afterBlock: IBlock, newBlock: IBlock, focusNewBlock: boolean = true): Promise<void> {
    const blocks = this.component.blocks;
    const blockIndex = blocks.findIndex((b: IBlock) => b.id === afterBlock.id);
    
    this.component.blocks = [
      ...blocks.slice(0, blockIndex + 1), 
      newBlock, 
      ...blocks.slice(blockIndex + 1)
    ];
    
    // Insert the new block element programmatically if we have the editor
    if (this.component.editorContentRef) {
      const afterWrapper = this.component.editorContentRef.querySelector(`[data-block-id="${afterBlock.id}"]`);
      if (afterWrapper) {
        const newWrapper = this.component.createBlockElement(newBlock);
        afterWrapper.insertAdjacentElement('afterend', newWrapper);
      }
    }
    
    this.component.updateValue();
    
    if (focusNewBlock && newBlock.type !== 'divider') {
      // Give DOM time to settle
      await new Promise(resolve => setTimeout(resolve, 0));
      
      // Focus the new block
      await this.focusBlock(newBlock.id, 'start');
    }
  }

  /**
   * Removes a block by its ID
   */
  removeBlock(blockId: string): void {
    // Save checkpoint before deletion
    this.component.saveToHistory(false);
    
    this.component.blocks = this.component.blocks.filter((b: IBlock) => b.id !== blockId);
    
    // Remove the block element programmatically if we have the editor
    if (this.component.editorContentRef) {
      const wrapper = this.component.editorContentRef.querySelector(`[data-block-id="${blockId}"]`);
      if (wrapper) {
        wrapper.remove();
      }
    }
    
    this.component.updateValue();
  }

  /**
   * Finds a block by its ID
   */
  findBlock(blockId: string): IBlock | undefined {
    return this.component.blocks.find((b: IBlock) => b.id === blockId);
  }

  /**
   * Gets the index of a block
   */
  getBlockIndex(blockId: string): number {
    return this.component.blocks.findIndex((b: IBlock) => b.id === blockId);
  }

  /**
   * Focuses a specific block
   */
  async focusBlock(blockId: string, cursorPosition: 'start' | 'end' | number = 'start'): Promise<void> {
    const wrapperElement = this.component.shadowRoot!.querySelector(`[data-block-id="${blockId}"]`);
    if (wrapperElement) {
      const blockComponent = wrapperElement.querySelector('dees-wysiwyg-block') as any;
      if (blockComponent) {
        // Wait a frame to ensure the block is rendered
        await new Promise(resolve => requestAnimationFrame(resolve));
        
        // Now focus with cursor position
        blockComponent.focusWithCursor(cursorPosition);
      }
    }
  }

  /**
   * Updates the content of a block
   */
  updateBlockContent(blockId: string, content: string): void {
    const block = this.findBlock(blockId);
    if (block) {
      block.content = content;
      this.component.updateValue();
    }
  }

  /**
   * Transforms a block to a different type
   */
  transformBlock(blockId: string, newType: IBlock['type'], metadata?: any): void {
    const block = this.findBlock(blockId);
    if (block) {
      // Save checkpoint before transformation
      this.component.saveToHistory(false);
      
      block.type = newType;
      block.content = '';
      if (metadata) {
        block.metadata = metadata;
      }
      
      // Update the block element programmatically if we have the editor
      if (this.component.editorContentRef) {
        this.component.updateBlockElement(blockId);
      }
      
      this.component.updateValue();
    }
  }

  /**
   * Moves a block to a new position
   */
  moveBlock(blockId: string, targetIndex: number): void {
    const blocks = [...this.component.blocks];
    const currentIndex = this.getBlockIndex(blockId);
    
    if (currentIndex === -1 || targetIndex < 0 || targetIndex >= blocks.length) {
      return;
    }
    
    const [movedBlock] = blocks.splice(currentIndex, 1);
    blocks.splice(targetIndex, 0, movedBlock);
    
    this.component.blocks = blocks;
    this.component.updateValue();
  }

  /**
   * Gets the previous block
   */
  getPreviousBlock(blockId: string): IBlock | null {
    const index = this.getBlockIndex(blockId);
    return index > 0 ? this.component.blocks[index - 1] : null;
  }

  /**
   * Gets the next block
   */
  getNextBlock(blockId: string): IBlock | null {
    const index = this.getBlockIndex(blockId);
    return index < this.component.blocks.length - 1 ? this.component.blocks[index + 1] : null;
  }
}