import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation, OnInit, OnDestroy, AfterViewInit, inject, ElementRef, Renderer2, ViewChild, HostListener, TemplateRef } from '@angular/core';
import { CommonModule, DOCUMENT } from '@angular/common';
import { signal, computed } from '@angular/core';

type ToolbarSize = 'sm' | 'md' | 'lg';
type ToolbarVariant = 'default' | 'elevated' | 'floating' | 'compact' | 'contextual';
type ToolbarPosition = 'top' | 'bottom' | 'left' | 'right';
type ToolbarAnimationType = 'slide-fade' | 'bounce' | 'none';

export interface ToolbarAction {
  id: string;
  label: string;
  icon?: string;
  iconTemplate?: TemplateRef<any>;
  disabled?: boolean;
  visible?: boolean;
  divider?: boolean;
  tooltip?: string;
  shortcut?: string;
  callback?: (action: ToolbarAction, event: Event) => void;
}

export interface ToolbarContext {
  type?: string;
  selection?: any;
  data?: any;
  metadata?: Record<string, any>;
}

export interface ToolbarPositionData {
  top: number;
  left: number;
  position: ToolbarPosition;
}

export interface FloatingToolbarConfig {
  size?: ToolbarSize;
  variant?: ToolbarVariant;
  position?: ToolbarPosition;
  autoPosition?: boolean;
  visible?: boolean;
  actions?: ToolbarAction[];
  context?: ToolbarContext;
  trigger?: 'manual' | 'selection' | 'hover' | 'contextmenu';
  autoHide?: boolean;
  hideDelay?: number;
  showAnimation?: ToolbarAnimationType;
  backdrop?: boolean;
  backdropClosable?: boolean;
  escapeClosable?: boolean;
  offset?: number;
  label?: string;
  showLabel?: boolean;
  showShortcuts?: boolean;
}

@Component({
  selector: 'ui-floating-toolbar',
  standalone: true,
  imports: [CommonModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  template: `
    @if (isVisible()) {
      <!-- Backdrop (optional) -->
      @if (backdrop) {
        <div 
          class="ui-floating-toolbar-backdrop"
          (click)="handleBackdropClick($event)"
        ></div>
      }

      <!-- Floating Toolbar Container -->
      <div 
        class="ui-floating-toolbar"
        [class.ui-floating-toolbar--{{size}}]="size"
        [class.ui-floating-toolbar--{{variant}}]="variant"
        [class.ui-floating-toolbar--{{computedPosition()}}]="computedPosition()"
        [class.ui-floating-toolbar--visible]="isVisible()"
        [class.ui-floating-toolbar--entering]="isEntering()"
        [class.ui-floating-toolbar--leaving]="isLeaving()"
        [class.ui-floating-toolbar--disabled]="disabled"
        [class.ui-floating-toolbar--{{showAnimation}}]="showAnimation !== 'none'"
        [style.top.px]="positionData().top"
        [style.left.px]="positionData().left"
        [attr.role]="'toolbar'"
        [attr.aria-label]="label || 'Floating toolbar'"
        [attr.aria-orientation]="'horizontal'"
        [attr.tabindex]="0"
        (keydown)="handleKeydown($event)"
        (click)="$event.stopPropagation()"
        #toolbarElement
      >
        <!-- Optional Label -->
        @if (label && showLabel) {
          <div class="ui-floating-toolbar__label">{{ label }}</div>
          <div class="ui-floating-toolbar__divider"></div>
        }

        <!-- Actions Container -->
        <div class="ui-floating-toolbar__actions">
          @for (action of visibleActions(); track action.id) {
            <!-- Divider -->
            @if (action.divider) {
              <div class="ui-floating-toolbar__divider"></div>
            }

            <!-- Action Button -->
            <button
              type="button"
              class="ui-floating-toolbar__action"
              [class.ui-floating-toolbar__action--disabled]="action.disabled"
              [disabled]="action.disabled"
              [attr.aria-label]="action.label"
              [attr.title]="action.tooltip || action.label"
              [attr.data-shortcut]="action.shortcut"
              (click)="handleActionClick(action, $event)"
              (keydown)="handleActionKeydown(action, $event)"
            >
              <!-- Icon (if provided) -->
              @if (action.icon) {
                <i [class]="action.icon" aria-hidden="true"></i>
              }

              <!-- Icon Template (if provided) -->
              @if (action.iconTemplate) {
                <ng-container *ngTemplateOutlet="action.iconTemplate"></ng-container>
              }

              <!-- Label (for screen readers or when no icon) -->
              <span 
                class="ui-floating-toolbar__action-label"
                [class.ui-floating-toolbar__action-label--visible]="!action.icon && !action.iconTemplate"
              >
                {{ action.label }}
              </span>

              <!-- Shortcut indicator -->
              @if (action.shortcut && showShortcuts) {
                <span class="ui-floating-toolbar__shortcut">{{ action.shortcut }}</span>
              }
            </button>
          }
        </div>

        <!-- Custom Content Slot -->
        <ng-content></ng-content>
      </div>
    }
  `,
  styleUrl: './floating-toolbar.component.scss'
})
export class FloatingToolbarComponent implements OnInit, OnDestroy, AfterViewInit {
  // Dependencies
  private elementRef = inject(ElementRef);
  private renderer = inject(Renderer2);
  private document = inject(DOCUMENT);

  // ViewChild references
  @ViewChild('toolbarElement', { static: false }) toolbarElement?: ElementRef<HTMLElement>;

  // Core Inputs
  @Input() size: ToolbarSize = 'md';
  @Input() variant: ToolbarVariant = 'default';
  @Input() position: ToolbarPosition = 'top';
  @Input() autoPosition = true;
  @Input() disabled = false;
  @Input() label = '';
  @Input() showLabel = false;
  @Input() showShortcuts = false;

  // Behavior Inputs
  @Input() trigger: 'manual' | 'selection' | 'hover' | 'contextmenu' = 'manual';
  @Input() autoHide = false;
  @Input() hideDelay = 3000;
  @Input() showAnimation: ToolbarAnimationType = 'slide-fade';
  @Input() backdrop = false;
  @Input() backdropClosable = true;
  @Input() escapeClosable = true;
  @Input() offset = 12;

  // Context and Actions
  @Input() actions: ToolbarAction[] = [];
  @Input() context?: ToolbarContext;

  // Reference element (anchor point)
  @Input() anchorElement?: HTMLElement;
  @Input() anchorSelector?: string;

  // State Input
  @Input() set visible(value: boolean) {
    if (value !== this._visible()) {
      this._visible.set(value);
      if (value) {
        this.show();
      } else {
        this.hide();
      }
    }
  }

  get visible(): boolean {
    return this._visible();
  }

  // Outputs
  @Output() visibleChange = new EventEmitter<boolean>();
  @Output() shown = new EventEmitter<void>();
  @Output() hidden = new EventEmitter<void>();
  @Output() actionClicked = new EventEmitter<{ action: ToolbarAction; event: Event }>();
  @Output() contextChanged = new EventEmitter<ToolbarContext>();
  @Output() positionChanged = new EventEmitter<ToolbarPosition>();
  @Output() backdropClicked = new EventEmitter<MouseEvent>();
  @Output() escapePressed = new EventEmitter<KeyboardEvent>();

  // Internal state signals
  private _visible = signal(false);
  private _entering = signal(false);
  private _leaving = signal(false);
  private _computedPosition = signal<ToolbarPosition>(this.position);
  private _positionData = signal<ToolbarPositionData>({ top: 0, left: 0, position: this.position });
  private _focusedActionIndex = signal(-1);

  // Computed signals
  readonly isVisible = computed(() => this._visible() || this._entering() || this._leaving());
  readonly isEntering = computed(() => this._entering());
  readonly isLeaving = computed(() => this._leaving());
  readonly computedPosition = computed(() => this._computedPosition());
  readonly positionData = computed(() => this._positionData());
  readonly visibleActions = computed(() => 
    this.actions.filter(action => action.visible !== false)
  );
  readonly focusedActionIndex = computed(() => this._focusedActionIndex());

  // Internal properties
  private hideTimer?: number;
  private showTimer?: number;
  private resizeObserver?: ResizeObserver;
  private selectionObserver?: MutationObserver;
  private currentSelection?: Selection | null;
  private animationDuration = 200; // ms

  // Unique ID for accessibility
  readonly toolbarId = `floating-toolbar-${Math.random().toString(36).substr(2, 9)}`;

  ngOnInit(): void {
    if (this.visible) {
      this.show();
    }
    this.setupTriggerListeners();
    this.setupAnchorElement();
  }

  ngAfterViewInit(): void {
    if (this.visible) {
      setTimeout(() => this.updatePosition(), 0);
    }
  }

  ngOnDestroy(): void {
    this.clearTimers();
    this.cleanup();
  }

  /**
   * Shows the floating toolbar with animation and positioning
   */
  show(): void {
    if (this._visible() || this.disabled) return;

    console.log('FloatingToolbar: show() called');
    this.clearTimers();
    
    this._visible.set(true);
    this._entering.set(true);
    this.visibleChange.emit(true);
    console.log('FloatingToolbar: visibility signals updated', { 
      visible: this._visible(), 
      entering: this._entering(),
      isVisible: this.isVisible()
    });
    
    this.updatePosition();
    this.setupPositionObservers();

    // Animation timing
    setTimeout(() => {
      this._entering.set(false);
      this.shown.emit();
      console.log('FloatingToolbar: animation completed');
      
      // Auto-hide if enabled
      if (this.autoHide && this.hideDelay > 0) {
        this.scheduleAutoHide();
      }
    }, this.animationDuration);
  }

  /**
   * Hides the floating toolbar with animation
   */
  hide(): void {
    if (!this._visible()) return;

    this.clearTimers();
    this.cleanup();

    this._leaving.set(true);

    // Animation timing
    setTimeout(() => {
      this._visible.set(false);
      this._leaving.set(false);
      this.visibleChange.emit(false);
      this.hidden.emit();
    }, this.animationDuration);
  }

  /**
   * Toggles toolbar visibility
   */
  toggle(): void {
    if (this._visible()) {
      this.hide();
    } else {
      this.show();
    }
  }

  /**
   * Updates toolbar actions based on context
   */
  updateContext(context: ToolbarContext): void {
    this.context = context;
    this.contextChanged.emit(context);
    
    // Update action visibility and state based on context
    this.updateActionsFromContext();
  }

  /**
   * Adds an action to the toolbar
   */
  addAction(action: ToolbarAction, index?: number): void {
    if (index !== undefined && index >= 0 && index < this.actions.length) {
      this.actions.splice(index, 0, action);
    } else {
      this.actions.push(action);
    }
  }

  /**
   * Removes an action from the toolbar
   */
  removeAction(actionId: string): void {
    const index = this.actions.findIndex(action => action.id === actionId);
    if (index !== -1) {
      this.actions.splice(index, 1);
    }
  }

  /**
   * Updates an existing action
   */
  updateAction(actionId: string, updates: Partial<ToolbarAction>): void {
    const action = this.actions.find(a => a.id === actionId);
    if (action) {
      Object.assign(action, updates);
    }
  }

  /**
   * Updates the toolbar position relative to the anchor element
   */
  updatePosition(): void {
    if (!this.anchorElement || !this.toolbarElement) {
      console.log('FloatingToolbar: updatePosition() - missing elements', {
        anchorElement: !!this.anchorElement,
        toolbarElement: !!this.toolbarElement
      });
      return;
    }

    const anchorRect = this.anchorElement.getBoundingClientRect();
    const toolbarEl = this.toolbarElement.nativeElement;
    const toolbarRect = toolbarEl.getBoundingClientRect();
    const viewportWidth = window.innerWidth;
    const viewportHeight = window.innerHeight;
    const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
    const scrollTop = window.pageYOffset || document.documentElement.scrollTop;

    let position = this.position;
    let top = 0;
    let left = 0;

    // Calculate initial position
    const positions = this.calculatePositions(anchorRect, toolbarRect, scrollLeft, scrollTop);
    const initialPos = positions[position];
    top = initialPos.top;
    left = initialPos.left;

    // Auto-position if enabled and toolbar goes outside viewport
    if (this.autoPosition) {
      const bestPosition = this.findBestPosition(positions, viewportWidth, viewportHeight, toolbarRect);
      position = bestPosition.position;
      top = bestPosition.top;
      left = bestPosition.left;
    }

    // Ensure toolbar stays within viewport bounds
    const finalPosition = this.constrainToViewport(
      { top, left, position },
      toolbarRect,
      viewportWidth,
      viewportHeight
    );

    // Update state
    this._computedPosition.set(finalPosition.position);
    this._positionData.set(finalPosition);

    // Emit position change if it changed
    if (finalPosition.position !== this.position) {
      this.positionChanged.emit(finalPosition.position);
    }
  }

  /**
   * Handles action button clicks
   */
  handleActionClick(action: ToolbarAction, event: Event): void {
    if (action.disabled) return;

    event.stopPropagation();
    
    // Execute action callback if provided
    if (action.callback) {
      action.callback(action, event);
    }

    // Emit action clicked event
    this.actionClicked.emit({ action, event });

    // Focus management
    const button = event.target as HTMLButtonElement;
    if (button) {
      const actionIndex = this.visibleActions().findIndex(a => a.id === action.id);
      this._focusedActionIndex.set(actionIndex);
    }
  }

  /**
   * Handles keyboard navigation within actions
   */
  handleActionKeydown(action: ToolbarAction, event: KeyboardEvent): void {
    const visibleActions = this.visibleActions();
    const currentIndex = this._focusedActionIndex();
    
    switch (event.key) {
      case 'ArrowLeft':
      case 'ArrowUp':
        event.preventDefault();
        this.focusPreviousAction();
        break;
        
      case 'ArrowRight':
      case 'ArrowDown':
        event.preventDefault();
        this.focusNextAction();
        break;
        
      case 'Home':
        event.preventDefault();
        this.focusFirstAction();
        break;
        
      case 'End':
        event.preventDefault();
        this.focusLastAction();
        break;
        
      case 'Enter':
      case ' ':
        event.preventDefault();
        this.handleActionClick(action, event);
        break;
    }
  }

  /**
   * Handles toolbar-level keyboard events
   */
  handleKeydown(event: KeyboardEvent): void {
    switch (event.key) {
      case 'Escape':
        if (this.escapeClosable) {
          event.preventDefault();
          this.hide();
          this.escapePressed.emit(event);
        }
        break;
        
      case 'Tab':
        // Allow normal tab behavior within toolbar
        break;
        
      default:
        // Handle keyboard shortcuts
        this.handleKeyboardShortcut(event);
        break;
    }
  }

  /**
   * Handles backdrop clicks
   */
  handleBackdropClick(event: MouseEvent): void {
    if (this.backdropClosable) {
      this.hide();
      this.backdropClicked.emit(event);
    }
  }

  /**
   * Document click listener to handle outside clicks
   */
  @HostListener('document:click', ['$event'])
  onDocumentClick(event: MouseEvent): void {
    if (!this._visible()) return;

    const target = event.target as HTMLElement;
    const isInsideToolbar = this.elementRef.nativeElement.contains(target);
    const isInsideAnchor = this.anchorElement?.contains(target);

    if (!isInsideToolbar && !isInsideAnchor && this.trigger !== 'manual') {
      this.hide();
    }
  }

  /**
   * Document selection change listener for text selection trigger
   */
  @HostListener('document:selectionchange', ['$event'])
  onDocumentSelectionChange(event: Event): void {
    if (this.trigger !== 'selection') return;

    const selection = window.getSelection();
    
    if (selection && selection.toString().trim()) {
      // Text is selected
      this.currentSelection = selection;
      this.updateSelectionAnchor();
      this.show();
    } else {
      // No text selected
      this.currentSelection = null;
      if (this.autoHide) {
        this.scheduleAutoHide();
      }
    }
  }

  /**
   * Focus management methods
   */
  private focusFirstAction(): void {
    const actions = this.visibleActions();
    if (actions.length > 0) {
      this._focusedActionIndex.set(0);
      this.focusActionButton(0);
    }
  }

  private focusLastAction(): void {
    const actions = this.visibleActions();
    if (actions.length > 0) {
      const lastIndex = actions.length - 1;
      this._focusedActionIndex.set(lastIndex);
      this.focusActionButton(lastIndex);
    }
  }

  private focusNextAction(): void {
    const actions = this.visibleActions();
    const currentIndex = this._focusedActionIndex();
    const nextIndex = (currentIndex + 1) % actions.length;
    this._focusedActionIndex.set(nextIndex);
    this.focusActionButton(nextIndex);
  }

  private focusPreviousAction(): void {
    const actions = this.visibleActions();
    const currentIndex = this._focusedActionIndex();
    const prevIndex = currentIndex <= 0 ? actions.length - 1 : currentIndex - 1;
    this._focusedActionIndex.set(prevIndex);
    this.focusActionButton(prevIndex);
  }

  private focusActionButton(index: number): void {
    if (!this.toolbarElement) return;

    const buttons = this.toolbarElement.nativeElement.querySelectorAll('.ui-floating-toolbar__action');
    const button = buttons[index] as HTMLButtonElement;
    if (button && !button.disabled) {
      button.focus();
    }
  }

  /**
   * Handles keyboard shortcuts
   */
  private handleKeyboardShortcut(event: KeyboardEvent): void {
    const shortcutKey = this.getShortcutString(event);
    const action = this.actions.find(a => a.shortcut === shortcutKey && !a.disabled && a.visible !== false);
    
    if (action) {
      event.preventDefault();
      this.handleActionClick(action, event);
    }
  }

  private getShortcutString(event: KeyboardEvent): string {
    const parts: string[] = [];
    
    if (event.ctrlKey) parts.push('Ctrl');
    if (event.altKey) parts.push('Alt');
    if (event.shiftKey) parts.push('Shift');
    if (event.metaKey) parts.push('Cmd');
    
    if (event.key && event.key !== 'Control' && event.key !== 'Alt' && event.key !== 'Shift' && event.key !== 'Meta') {
      parts.push(event.key);
    }
    
    return parts.join('+');
  }

  /**
   * Sets up trigger listeners based on trigger type
   */
  private setupTriggerListeners(): void {
    switch (this.trigger) {
      case 'hover':
        if (this.anchorElement) {
          this.renderer.listen(this.anchorElement, 'mouseenter', () => this.show());
          this.renderer.listen(this.anchorElement, 'mouseleave', () => {
            if (this.autoHide) {
              this.scheduleAutoHide();
            }
          });
          
          // Keep toolbar open when hovering over it
          this.renderer.listen(this.elementRef.nativeElement, 'mouseenter', () => {
            this.clearTimers();
          });
          this.renderer.listen(this.elementRef.nativeElement, 'mouseleave', () => {
            if (this.autoHide) {
              this.scheduleAutoHide();
            }
          });
        }
        break;

      case 'contextmenu':
        if (this.anchorElement) {
          this.renderer.listen(this.anchorElement, 'contextmenu', (event: MouseEvent) => {
            event.preventDefault();
            this.updatePositionFromEvent(event);
            this.show();
          });
        }
        break;

      case 'selection':
        // Handled by document listener
        break;

      case 'manual':
      default:
        // No automatic triggers
        break;
    }
  }

  private setupAnchorElement(): void {
    if (this.anchorSelector && !this.anchorElement) {
      const element = this.document.querySelector(this.anchorSelector) as HTMLElement;
      if (element) {
        this.anchorElement = element;
        this.setupTriggerListeners();
      }
    }
  }

  private updateSelectionAnchor(): void {
    if (!this.currentSelection) return;

    const range = this.currentSelection.getRangeAt(0);
    const rect = range.getBoundingClientRect();
    
    // Create a temporary anchor element for positioning
    if (rect.width > 0 && rect.height > 0) {
      this.anchorElement = {
        getBoundingClientRect: () => rect,
        contains: () => false
      } as unknown as HTMLElement;
    }
  }

  private updatePositionFromEvent(event: MouseEvent): void {
    // Create a temporary anchor element at the event position
    this.anchorElement = {
      getBoundingClientRect: () => ({
        top: event.clientY,
        left: event.clientX,
        right: event.clientX,
        bottom: event.clientY,
        width: 0,
        height: 0
      } as DOMRect),
      contains: () => false
    } as unknown as HTMLElement;
  }

  private updateActionsFromContext(): void {
    if (!this.context) return;

    // Update action visibility and state based on context
    this.actions.forEach(action => {
      // This could be enhanced with more sophisticated context-aware logic
      if (this.context?.type && action.id.includes(this.context.type)) {
        action.visible = true;
      }
    });
  }

  private scheduleAutoHide(): void {
    this.clearTimers();
    this.hideTimer = window.setTimeout(() => {
      this.hide();
    }, this.hideDelay);
  }

  private clearTimers(): void {
    if (this.hideTimer) {
      clearTimeout(this.hideTimer);
      this.hideTimer = undefined;
    }
    if (this.showTimer) {
      clearTimeout(this.showTimer);
      this.showTimer = undefined;
    }
  }

  private setupPositionObservers(): void {
    // Resize observer for position updates
    this.resizeObserver = new ResizeObserver(() => {
      if (this._visible()) {
        this.updatePosition();
      }
    });
    this.resizeObserver.observe(document.body);

    // Listen for window scroll and resize
    window.addEventListener('scroll', this.updatePositionThrottled, { passive: true });
    window.addEventListener('resize', this.updatePositionThrottled, { passive: true });
  }

  private updatePositionThrottled = this.throttle(() => {
    if (this._visible()) {
      this.updatePosition();
    }
  }, 16); // ~60fps

  private cleanup(): void {
    this.resizeObserver?.disconnect();
    this.selectionObserver?.disconnect();
    window.removeEventListener('scroll', this.updatePositionThrottled);
    window.removeEventListener('resize', this.updatePositionThrottled);
  }

  private calculatePositions(
    anchorRect: DOMRect,
    toolbarRect: DOMRect,
    scrollLeft: number,
    scrollTop: number
  ): Record<ToolbarPosition, ToolbarPositionData> {
    const anchorCenterX = anchorRect.left + anchorRect.width / 2;
    const anchorCenterY = anchorRect.top + anchorRect.height / 2;

    return {
      'top': {
        top: anchorRect.top - toolbarRect.height - this.offset + scrollTop,
        left: anchorCenterX - toolbarRect.width / 2 + scrollLeft,
        position: 'top'
      },
      'bottom': {
        top: anchorRect.bottom + this.offset + scrollTop,
        left: anchorCenterX - toolbarRect.width / 2 + scrollLeft,
        position: 'bottom'
      },
      'left': {
        top: anchorCenterY - toolbarRect.height / 2 + scrollTop,
        left: anchorRect.left - toolbarRect.width - this.offset + scrollLeft,
        position: 'left'
      },
      'right': {
        top: anchorCenterY - toolbarRect.height / 2 + scrollTop,
        left: anchorRect.right + this.offset + scrollLeft,
        position: 'right'
      }
    };
  }

  private findBestPosition(
    positions: Record<ToolbarPosition, ToolbarPositionData>,
    viewportWidth: number,
    viewportHeight: number,
    toolbarRect: DOMRect
  ): ToolbarPositionData {
    const preferenceOrder: ToolbarPosition[] = [
      this.position,
      ...Object.keys(positions).filter(p => p !== this.position) as ToolbarPosition[]
    ];

    for (const pos of preferenceOrder) {
      const posData = positions[pos];
      const fitsHorizontally = posData.left >= 0 && posData.left + toolbarRect.width <= viewportWidth;
      const fitsVertically = posData.top >= 0 && posData.top + toolbarRect.height <= viewportHeight;

      if (fitsHorizontally && fitsVertically) {
        return posData;
      }
    }

    return positions[this.position];
  }

  private constrainToViewport(
    position: ToolbarPositionData,
    toolbarRect: DOMRect,
    viewportWidth: number,
    viewportHeight: number
  ): ToolbarPositionData {
    const margin = 8;
    let { top, left } = position;

    // Constrain horizontally
    if (left < margin) {
      left = margin;
    } else if (left + toolbarRect.width > viewportWidth - margin) {
      left = viewportWidth - toolbarRect.width - margin;
    }

    // Constrain vertically
    if (top < margin) {
      top = margin;
    } else if (top + toolbarRect.height > viewportHeight - margin) {
      top = viewportHeight - toolbarRect.height - margin;
    }

    return { ...position, top, left };
  }

  private throttle<T extends (...args: any[]) => void>(func: T, limit: number): T {
    let inThrottle: boolean;
    return ((...args: any[]) => {
      if (!inThrottle) {
        func.apply(this, args);
        inThrottle = true;
        setTimeout(() => inThrottle = false, limit);
      }
    }) as T;
  }

  /**
   * Public API method to apply configuration
   */
  configure(config: FloatingToolbarConfig): void {
    Object.assign(this, config);
  }

  /**
   * Public API method to set anchor element
   */
  setAnchorElement(element: HTMLElement): void {
    this.anchorElement = element;
    this.setupTriggerListeners();
  }
}