import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation, OnInit, OnDestroy, inject, ElementRef, HostListener } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { faXmark } from '@fortawesome/free-solid-svg-icons';
import { signal, computed } from '@angular/core';

type DrawerSize = 'sm' | 'md' | 'lg' | 'xl';
type DrawerPosition = 'left' | 'right' | 'top' | 'bottom';
type FooterAlignment = 'start' | 'center' | 'end' | 'between';

export interface DrawerConfig {
  size?: DrawerSize;
  position?: DrawerPosition;
  closable?: boolean;
  backdropClosable?: boolean;
  escapeClosable?: boolean;
  showHeader?: boolean;
  showFooter?: boolean;
  headerBorder?: boolean;
  footerBorder?: boolean;
  bodyPadding?: boolean;
  bodyScrollable?: boolean;
  footerAlignment?: FooterAlignment;
  preventBodyScroll?: boolean;
  focusTrap?: boolean;
  persistent?: boolean;
}

@Component({
  selector: 'ui-drawer',
  standalone: true,
  imports: [CommonModule, FontAwesomeModule],
  changeDetection: ChangeDetectionStrategy.Default,
  encapsulation: ViewEncapsulation.None,
  template: `
    @if (isVisible()) {
      <div 
        class="ui-drawer"
        [class.ui-drawer--{{size}}]="size"
        [class.ui-drawer--{{position}}]="position"
        [class.ui-drawer--loading]="loading"
        [class.ui-drawer--persistent]="persistent"
        role="dialog"
        [attr.aria-modal]="!persistent"
        [attr.aria-labelledby]="titleId"
        [attr.aria-describedby]="contentId"
        (keydown)="handleKeydown($event)"
      >
        <!-- Drawer Backdrop -->
        @if (!persistent) {
          <div 
            class="ui-drawer__backdrop"
            [class.ui-drawer__backdrop--visible]="isVisible()"
            [class.ui-drawer__backdrop--entering]="isEntering()"
            [class.ui-drawer__backdrop--leaving]="isLeaving()"
            (click)="handleBackdropClick($event)"
          ></div>
        }
        
        <!-- Drawer Container -->
        <div 
          class="ui-drawer__container"
          [class.ui-drawer__container--visible]="isVisible()"
          [class.ui-drawer__container--entering]="isEntering()"
          [class.ui-drawer__container--leaving]="isLeaving()"
          (click)="$event.stopPropagation()"
          #drawerContainer
        >
          <!-- Drawer Header -->
          @if (showHeader) {
            <div 
              class="ui-drawer__header"
              [class.ui-drawer__header--no-border]="!headerBorder"
            >
              <h2 
                class="ui-drawer__title" 
                [id]="titleId"
              >
                @if (title) {
                  {{ title }}
                } @else {
                  <ng-content select="[slot='title']"></ng-content>
                }
              </h2>
              
              @if (closable) {
                <button 
                  type="button"
                  class="ui-drawer__close-button"
                  (click)="close()"
                  [attr.aria-label]="closeAriaLabel"
                  #closeButton
                >
                  <fa-icon [icon]="faXmark"></fa-icon>
                </button>
              }
            </div>
          }

          <!-- Drawer Body -->
          <div 
            class="ui-drawer__body"
            [class.ui-drawer__body--no-padding]="!bodyPadding"
            [class.ui-drawer__body--scrollable]="bodyScrollable"
            [id]="contentId"
          >
            @if (loading) {
              <div class="ui-drawer__loader" role="status" aria-label="Loading"></div>
            } @else {
              <div class="ui-drawer__content">
                <ng-content></ng-content>
              </div>
            }
          </div>

          <!-- Drawer Footer -->
          @if (showFooter) {
            <div 
              class="ui-drawer__footer"
              [class.ui-drawer__footer--no-border]="!footerBorder"
              [class.ui-drawer__footer--start]="footerAlignment === 'start'"
              [class.ui-drawer__footer--center]="footerAlignment === 'center'"
              [class.ui-drawer__footer--between]="footerAlignment === 'between'"
            >
              <ng-content select="[slot='footer']"></ng-content>
            </div>
          }
        </div>
      </div>
    }
  `,
  styleUrl: './drawer.component.scss'
})
export class DrawerComponent implements OnInit, OnDestroy {
  // Dependencies
  private elementRef = inject(ElementRef);

  // Icons
  readonly faXmark = faXmark;

  // Inputs
  @Input() size: DrawerSize = 'md';
  @Input() position: DrawerPosition = 'left';
  @Input() title = '';
  @Input() loading = false;
  @Input() closable = true;
  @Input() backdropClosable = true;
  @Input() escapeClosable = true;
  @Input() showHeader = true;
  @Input() showFooter = false;
  @Input() headerBorder = true;
  @Input() footerBorder = true;
  @Input() bodyPadding = true;
  @Input() bodyScrollable = true;
  @Input() footerAlignment: FooterAlignment = 'end';
  @Input() preventBodyScroll = true;
  @Input() focusTrap = true;
  @Input() persistent = false;
  @Input() closeAriaLabel = 'Close drawer';

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

  get open(): boolean {
    return this._open();
  }

  // Outputs
  @Output() openChange = new EventEmitter<boolean>();
  @Output() opened = new EventEmitter<void>();
  @Output() closed = new EventEmitter<void>();
  @Output() backdropClicked = new EventEmitter<void>();
  @Output() escapePressed = new EventEmitter<void>();

  // Internal state signals
  private _open = signal(false);
  private _entering = signal(false);
  private _leaving = signal(false);

  // Computed signals
  readonly isVisible = computed(() => this._open() || this._entering() || this._leaving());
  readonly isEntering = computed(() => this._entering());
  readonly isLeaving = computed(() => this._leaving());

  // Internal properties
  private originalBodyOverflow = '';
  private originalBodyPaddingRight = '';
  private focusableElements: HTMLElement[] = [];
  private previousActiveElement: Element | null = null;
  private currentFocusIndex = 0;

  // Unique IDs for accessibility
  readonly titleId = `drawer-title-${Math.random().toString(36).substr(2, 9)}`;
  readonly contentId = `drawer-content-${Math.random().toString(36).substr(2, 9)}`;

  ngOnInit(): void {
    if (this.open) {
      this.show();
    }
  }

  ngOnDestroy(): void {
    this.restoreBodyScroll();
    this.restoreFocus();
  }

  /**
   * Shows the drawer with animation
   */
  show(): void {
    if (this._open()) return;

    if (this.preventBodyScroll && !this.persistent) {
      this.preventBodyScrollAction();
    }
    this.storePreviousFocus();
    
    this._open.set(true);
    this._entering.set(true);
    this.openChange.emit(true);

    // Animation timing
    setTimeout(() => {
      this._entering.set(false);
      this.setupFocusTrap();
      this.opened.emit();
    }, 300);
  }

  /**
   * Hides the drawer with animation
   */
  hide(): void {
    if (!this._open()) return;

    this._leaving.set(true);

    // Animation timing
    setTimeout(() => {
      this._open.set(false);
      this._leaving.set(false);
      this.restoreBodyScroll();
      this.restoreFocus();
      this.openChange.emit(false);
      this.closed.emit();
    }, 300);
  }

  /**
   * Toggles the drawer open/closed state
   */
  toggle(): void {
    if (this.open) {
      this.close();
    } else {
      this.open = true;
    }
  }

  /**
   * Closes the drawer
   */
  close(): void {
    this.open = false;
  }

  /**
   * Handles backdrop click events
   */
  handleBackdropClick(event: MouseEvent): void {
    event.stopPropagation();
    this.backdropClicked.emit();
    
    if (this.backdropClosable && !this.persistent) {
      this.close();
    }
  }

  /**
   * Handles keyboard events for accessibility
   */
  @HostListener('keydown', ['$event'])
  handleKeydown(event: KeyboardEvent): void {
    if (event.key === 'Escape' && this.escapeClosable) {
      event.preventDefault();
      this.escapePressed.emit();
      this.close();
    }

    if (this.focusTrap && this.isVisible()) {
      this.handleFocusTrap(event);
    }
  }

  /**
   * Prevents body scrolling by manipulating body styles
   */
  private preventBodyScrollAction(): void {
    const body = document.body;
    this.originalBodyOverflow = body.style.overflow;
    this.originalBodyPaddingRight = body.style.paddingRight;

    // Calculate scrollbar width to prevent layout shift
    const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
    
    body.style.overflow = 'hidden';
    if (scrollbarWidth > 0) {
      body.style.paddingRight = `${scrollbarWidth}px`;
    }
  }

  /**
   * Restores body scrolling
   */
  private restoreBodyScroll(): void {
    const body = document.body;
    body.style.overflow = this.originalBodyOverflow;
    body.style.paddingRight = this.originalBodyPaddingRight;
  }

  /**
   * Stores the currently focused element before showing drawer
   */
  private storePreviousFocus(): void {
    this.previousActiveElement = document.activeElement;
  }

  /**
   * Restores focus to the previously focused element
   */
  private restoreFocus(): void {
    if (this.previousActiveElement && this.previousActiveElement instanceof HTMLElement) {
      setTimeout(() => {
        if (this.previousActiveElement instanceof HTMLElement) {
          this.previousActiveElement.focus();
        }
        this.previousActiveElement = null;
      }, 100);
    }
  }

  /**
   * Sets up focus trap for accessibility
   */
  private setupFocusTrap(): void {
    if (!this.focusTrap) return;

    const drawerElement = this.elementRef.nativeElement.querySelector('.ui-drawer__container');
    if (drawerElement) {
      this.focusableElements = this.getFocusableElements(drawerElement);
      if (this.focusableElements.length > 0) {
        this.focusableElements[0].focus();
        this.currentFocusIndex = 0;
      }
    }
  }

  /**
   * Gets all focusable elements within the drawer
   */
  private getFocusableElements(container: Element): HTMLElement[] {
    const focusableSelectors = [
      'button:not([disabled])',
      'input:not([disabled])',
      'textarea:not([disabled])',
      'select:not([disabled])',
      'a[href]',
      '[tabindex]:not([tabindex="-1"])',
      '[contenteditable="true"]'
    ];

    return Array.from(container.querySelectorAll(focusableSelectors.join(', '))) as HTMLElement[];
  }

  /**
   * Handles focus trap keyboard navigation
   */
  private handleFocusTrap(event: KeyboardEvent): void {
    if (event.key !== 'Tab' || this.focusableElements.length === 0) return;

    if (event.shiftKey) {
      // Shift + Tab (backward)
      this.currentFocusIndex = this.currentFocusIndex <= 0 
        ? this.focusableElements.length - 1 
        : this.currentFocusIndex - 1;
    } else {
      // Tab (forward)
      this.currentFocusIndex = this.currentFocusIndex >= this.focusableElements.length - 1 
        ? 0 
        : this.currentFocusIndex + 1;
    }

    event.preventDefault();
    this.focusableElements[this.currentFocusIndex].focus();
  }
}