import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation, HostListener, ElementRef, inject } from '@angular/core';
import { CommonModule } from '@angular/common';

export type FabMenuSize = 'sm' | 'md' | 'lg';
export type FabMenuPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
export type FabMenuVariant = 'primary' | 'secondary' | 'success' | 'danger';
export type FabMenuDirection = 'up' | 'down' | 'left' | 'right' | 'auto';

export interface FabMenuItem {
  id: string;
  label: string;
  icon?: string;
  disabled?: boolean;
  variant?: FabMenuVariant;
}

@Component({
  selector: 'ui-fab-menu',
  standalone: true,
  imports: [CommonModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  template: `
    <div 
      [class]="getFabMenuClasses()">
      
      <!-- Menu Items -->
      @if (isOpen) {
        <div class="ui-fab-menu__items" role="menu">
          @for (item of menuItems; track item.id) {
            <button
              type="button"
              [class]="getItemClasses(item)"
              [disabled]="item.disabled || disabled"
              [attr.aria-label]="item.label"
              role="menuitem"
              [tabindex]="isOpen ? 0 : -1"
              (click)="handleItemClick(item, $event)"
              (keydown)="handleItemKeydown(item, $event)">
              
              @if (item.icon) {
                <span class="ui-fab-menu__item-icon" [innerHTML]="item.icon"></span>
              }
              
              <span class="ui-fab-menu__item-label">{{ item.label }}</span>
              
              <div class="ui-fab-menu__item-ripple"></div>
            </button>
          }
        </div>
      }
      
      <!-- Main FAB Button -->
      <button
        type="button"
        [class]="getTriggerClasses()"
        [disabled]="disabled"
        [attr.aria-expanded]="isOpen"
        [attr.aria-haspopup]="true"
        [attr.aria-label]="triggerLabel"
        role="button"
        (click)="toggle($event)"
        (keydown)="handleTriggerKeydown($event)">
        
        @if (isOpen && closeIcon) {
          <span class="ui-fab-menu__trigger-icon ui-fab-menu__trigger-icon--close" [innerHTML]="closeIcon"></span>
        } @else if (triggerIcon) {
          <span class="ui-fab-menu__trigger-icon ui-fab-menu__trigger-icon--open" [innerHTML]="triggerIcon"></span>
        }
        
        <ng-content></ng-content>
        
        <div class="ui-fab-menu__trigger-ripple"></div>
      </button>
      
      <!-- Backdrop -->
      @if (isOpen && backdrop) {
        <div 
          class="ui-fab-menu__backdrop"
          (click)="close()"
          role="presentation"></div>
      }
    </div>
  `,
  styleUrl: './fab-menu.component.scss'
})
export class FabMenuComponent {
  @Input() size: FabMenuSize = 'md';
  @Input() variant: FabMenuVariant = 'primary';
  @Input() position: FabMenuPosition = 'bottom-right';
  @Input() direction: FabMenuDirection = 'auto';
  @Input() menuItems: FabMenuItem[] = [];
  @Input() disabled = false;
  @Input() triggerIcon?: string;
  @Input() closeIcon?: string;
  @Input() triggerLabel = 'Open menu';
  @Input() backdrop = true;
  @Input() closeOnItemClick = true;
  @Input() closeOnOutsideClick = true;
  
  @Output() opened = new EventEmitter<void>();
  @Output() closed = new EventEmitter<void>();
  @Output() itemClicked = new EventEmitter<{item: FabMenuItem, event: Event}>();
  
  private elementRef = inject(ElementRef);
  
  isOpen = false;
  isAnimating = false;
  
  get actualDirection(): FabMenuDirection {
    if (this.direction !== 'auto') return this.direction;
    
    // Auto-determine direction based on position
    switch (this.position) {
      case 'bottom-right':
      case 'bottom-left':
        return 'up';
      case 'top-right':
      case 'top-left':
        return 'down';
      default:
        return 'up';
    }
  }

  getFabMenuClasses(): string {
    return [
      'ui-fab-menu',
      `ui-fab-menu--${this.size}`,
      `ui-fab-menu--${this.variant}`,
      `ui-fab-menu--${this.position}`,
      `ui-fab-menu--${this.actualDirection}`,
      this.isOpen ? 'ui-fab-menu--open' : '',
      this.disabled ? 'ui-fab-menu--disabled' : '',
      this.isAnimating ? 'ui-fab-menu--animating' : ''
    ].filter(Boolean).join(' ');
  }

  getTriggerClasses(): string {
    return [
      'ui-fab-menu__trigger',
      `ui-fab-menu__trigger--${this.size}`,
      `ui-fab-menu__trigger--${this.variant}`,
      this.isOpen ? 'ui-fab-menu__trigger--active' : ''
    ].filter(Boolean).join(' ');
  }

  getItemClasses(item: FabMenuItem): string {
    const variant = item.variant || this.variant;
    return [
      'ui-fab-menu__item',
      `ui-fab-menu__item--${variant}`,
      item.disabled ? 'ui-fab-menu__item--disabled' : ''
    ].filter(Boolean).join(' ');
  }
  
  @HostListener('document:click', ['$event'])
  onDocumentClick(event: Event): void {
    const target = event.target as Node;
    if (this.closeOnOutsideClick && this.isOpen && target && !this.elementRef.nativeElement.contains(target)) {
      this.close();
    }
  }
  
  @HostListener('keydown.escape')
  onEscapePress(): void {
    if (this.isOpen) {
      this.close();
    }
  }
  
  toggle(event?: Event): void {
    if (this.disabled) return;
    
    if (this.isOpen) {
      this.close();
    } else {
      this.open();
    }
  }
  
  open(): void {
    if (this.disabled || this.isOpen) return;
    
    this.isAnimating = true;
    this.isOpen = true;
    this.opened.emit();
    
    // Focus first menu item after animation
    setTimeout(() => {
      this.isAnimating = false;
      this.focusFirstMenuItem();
    }, 200);
  }
  
  close(): void {
    if (!this.isOpen) return;
    
    this.isAnimating = true;
    this.isOpen = false;
    this.closed.emit();
    
    setTimeout(() => {
      this.isAnimating = false;
    }, 200);
  }
  
  handleItemClick(item: FabMenuItem, event: Event): void {
    if (item.disabled || this.disabled) return;
    
    this.itemClicked.emit({ item, event });
    
    if (this.closeOnItemClick) {
      this.close();
    }
  }
  
  handleTriggerKeydown(event: KeyboardEvent): void {
    switch (event.key) {
      case 'Enter':
      case ' ':
        event.preventDefault();
        this.toggle();
        break;
      case 'ArrowUp':
        if (this.actualDirection === 'up') {
          event.preventDefault();
          if (!this.isOpen) this.open();
        }
        break;
      case 'ArrowDown':
        if (this.actualDirection === 'down') {
          event.preventDefault();
          if (!this.isOpen) this.open();
        }
        break;
    }
  }
  
  handleItemKeydown(item: FabMenuItem, event: KeyboardEvent): void {
    switch (event.key) {
      case 'Enter':
      case ' ':
        event.preventDefault();
        this.handleItemClick(item, event);
        break;
      case 'ArrowUp':
        event.preventDefault();
        this.focusPreviousItem(event.target as HTMLElement);
        break;
      case 'ArrowDown':
        event.preventDefault();
        this.focusNextItem(event.target as HTMLElement);
        break;
      case 'Tab':
        if (event.shiftKey) {
          this.focusPreviousItem(event.target as HTMLElement);
        } else {
          this.focusNextItem(event.target as HTMLElement);
        }
        break;
    }
  }
  
  private focusFirstMenuItem(): void {
    const firstItem = this.elementRef.nativeElement.querySelector('.ui-fab-menu__item:not([disabled])');
    if (firstItem) {
      firstItem.focus();
    }
  }
  
  private focusNextItem(currentElement: HTMLElement): void {
    const items = Array.from(this.elementRef.nativeElement.querySelectorAll('.ui-fab-menu__item:not([disabled])'));
    const currentIndex = items.indexOf(currentElement);
    const nextIndex = (currentIndex + 1) % items.length;
    (items[nextIndex] as HTMLElement).focus();
  }
  
  private focusPreviousItem(currentElement: HTMLElement): void {
    const items = Array.from(this.elementRef.nativeElement.querySelectorAll('.ui-fab-menu__item:not([disabled])'));
    const currentIndex = items.indexOf(currentElement);
    const previousIndex = currentIndex === 0 ? items.length - 1 : currentIndex - 1;
    (items[previousIndex] as HTMLElement).focus();
  }
}