import {
  Component,
  input,
  output,
  signal,
  HostListener,
  ViewChild,
  ElementRef,
  AfterViewInit,
  OnInit,
  inject
} from '@angular/core';
import { ThemeNodeDirective } from '../../../domains/theme';
import { ViewportService } from '../../../core/platform';
import { APP_TRANSLATE_IMPORTS } from '../../../core/i18n';
import { BottomSheetComponent } from '../bottom-sheet/bottom-sheet.component';

@Component({
  selector: 'app-context-menu',
  standalone: true,
  imports: [
    ThemeNodeDirective,
    BottomSheetComponent,
    ...APP_TRANSLATE_IMPORTS
  ],
  templateUrl: './context-menu.component.html',
  styleUrl: './context-menu.component.scss'
})
/* eslint-disable @typescript-eslint/member-ordering */
export class ContextMenuComponent implements OnInit, AfterViewInit {
  x = input.required<number>();
  y = input.required<number>();
  width = input<string>('w-48');
  widthPx = input<number | null>(null);
  /** Optional title shown when the menu is presented as a mobile bottom sheet. */
  sheetTitle = input<string | null>(null);
  closed = output<undefined>();

  @ViewChild('panel', { static: false }) panelRef?: ElementRef<HTMLDivElement>;

  private readonly viewport = inject(ViewportService);
  readonly isMobile = this.viewport.isMobile;

  clampedX = signal(0);
  clampedY = signal(0);

  ngOnInit(): void {
    if (this.isMobile()) {
      return;
    }

    this.clampedX.set(this.clampX(this.x(), this.estimateWidth()));
    this.clampedY.set(this.clampY(this.y(), 80));
  }

  ngAfterViewInit(): void {
    if (this.isMobile() || !this.panelRef) {
      return;
    }

    const rect = this.panelRef.nativeElement.getBoundingClientRect();

    this.clampedX.set(this.clampX(this.x(), rect.width));
    this.clampedY.set(this.clampY(this.y(), rect.height));
  }

  @HostListener('document:keydown.escape')
  onEscape(): void {
    this.closed.emit(undefined);
  }

  private estimateWidth(): number {
    const px = this.widthPx();

    if (px)
      return px;

    const match = this.width().match(/w-(\d+)/);

    return match ? parseInt(match[1], 10) * 4 : 192;
  }

  private clampX(rawX: number, panelWidth: number): number {
    const margin = 8;
    const maxX = window.innerWidth - panelWidth - margin;

    return Math.max(margin, Math.min(rawX, maxX));
  }

  private clampY(rawY: number, panelHeight: number): number {
    const margin = 8;
    const maxY = window.innerHeight - panelHeight - margin;

    return Math.max(margin, Math.min(rawY, maxY));
  }
}
