import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
import { signal, computed } from '@angular/core';

type BackdropVariant = 'default' | 'blur' | 'dark' | 'light';

export interface BackdropConfig {
  variant?: BackdropVariant;
  visible?: boolean;
  clickable?: boolean;
  blur?: boolean;
  opacity?: number;
  zIndex?: number;
  preventBodyScroll?: boolean;
}

@Component({
  selector: 'ui-backdrop',
  standalone: true,
  imports: [CommonModule],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  template: `
    @if (isVisible()) {
      <div 
        class="ui-backdrop"
        [class.ui-backdrop--{{variant}}]="variant"
        [class.ui-backdrop--blur]="blur"
        [class.ui-backdrop--clickable]="clickable"
        [class.ui-backdrop--visible]="isVisible()"
        [class.ui-backdrop--entering]="isEntering()"
        [class.ui-backdrop--leaving]="isLeaving()"
        [style.--backdrop-opacity]="opacity"
        [style.--backdrop-z-index]="zIndex"
        [attr.aria-hidden]="true"
        [attr.data-backdrop]="true"
        (click)="handleClick($event)"
        (animationend)="handleAnimationEnd($event)"
      >
        <ng-content></ng-content>
      </div>
    }
  `,
  styleUrl: './backdrop.component.scss'
})
export class BackdropComponent {
  // Inputs
  @Input() variant: BackdropVariant = 'default';
  @Input() clickable = true;
  @Input() blur = false;
  @Input() opacity = 0.5;
  @Input() zIndex = 1000;
  @Input() preventBodyScroll = false;

  // State Inputs
  @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() clicked = new EventEmitter<MouseEvent>();
  @Output() shown = new EventEmitter<void>();
  @Output() hidden = new EventEmitter<void>();

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

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

  // Internal properties
  private originalBodyOverflow = '';

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

    if (this.preventBodyScroll) {
      this.preventBodyScrollAction();
    }
    
    this._visible.set(true);
    this._entering.set(true);
    this.visibleChange.emit(true);

    // Animation timing
    setTimeout(() => {
      this._entering.set(false);
      this.shown.emit();
    }, 200);
  }

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

    this._leaving.set(true);

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

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

  /**
   * Handles click events
   */
  handleClick(event: MouseEvent): void {
    if (this.clickable) {
      this.clicked.emit(event);
    }
  }

  /**
   * Handles animation end events
   */
  handleAnimationEnd(event: AnimationEvent): void {
    // Additional animation handling can be added here if needed
    event.stopPropagation();
  }

  /**
   * Prevents body scrolling
   */
  private preventBodyScrollAction(): void {
    const body = document.body;
    this.originalBodyOverflow = body.style.overflow;
    body.style.overflow = 'hidden';
  }

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

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