import { CommonModule } from '@angular/common';
import {
  Component,
  HostListener,
  OnDestroy,
  computed,
  effect,
  inject,
  input,
  output,
  signal
} from '@angular/core';
import { NgIcon, provideIcons } from '@ng-icons/core';
import {
  lucideChevronLeft,
  lucideChevronRight,
  lucideCopy,
  lucideDownload,
  lucideX
} from '@ng-icons/lucide';
import { Attachment } from '../../../../../attachment';
import { canStepLightbox } from '../../../../domain/rules/chat-message-lightbox.rules';
import { AppI18nService, APP_TRANSLATE_IMPORTS } from '../../../../../../core/i18n';
import { ContextMenuComponent, ModalBackdropComponent } from '../../../../../../shared';
import {
  ChatLightboxState,
  ChatMessageImageGalleryEvent,
  ChatMessageImageContextMenuEvent,
  ChatMessageImageLightboxEvent
} from '../../models/chat-messages.model';

@Component({
  selector: 'app-chat-message-overlays',
  standalone: true,
  imports: [
    CommonModule,
    NgIcon,
    ContextMenuComponent,
    ModalBackdropComponent,
    ...APP_TRANSLATE_IMPORTS
  ],
  viewProviders: [
    provideIcons({
      lucideChevronLeft,
      lucideChevronRight,
      lucideCopy,
      lucideDownload,
      lucideX
    })
  ],
  templateUrl: './chat-message-overlays.component.html',
  styleUrl: './chat-message-overlays.component.scss',
  host: {
    style: 'display: contents;'
  }
})
export class ChatMessageOverlaysComponent implements OnDestroy {
  readonly lightboxControlsVisible = signal(true);
  readonly lightboxState = input<ChatLightboxState | null>(null);
  readonly galleryAttachments = input<ChatMessageImageGalleryEvent | null>(null);
  readonly imageContextMenu = input<ChatMessageImageContextMenuEvent | null>(null);

  readonly lightboxClosed = output();
  readonly lightboxStepRequested = output<number>();
  readonly galleryClosed = output();
  readonly contextMenuClosed = output();
  readonly downloadRequested = output<Attachment>();
  readonly copyRequested = output<Attachment>();
  readonly imageOpened = output<ChatMessageImageLightboxEvent>();
  readonly imageContextMenuRequested = output<ChatMessageImageContextMenuEvent>();

  readonly lightboxAttachment = computed(() => {
    const state = this.lightboxState();

    if (!state) {
      return null;
    }

    return state.attachments[state.index] ?? null;
  });

  readonly canShowPreviousLightboxImage = computed(() => {
    const state = this.lightboxState();

    if (!state) {
      return false;
    }

    return canStepLightbox(state.index, -1, state.attachments.length);
  });

  readonly canShowNextLightboxImage = computed(() => {
    const state = this.lightboxState();

    if (!state) {
      return false;
    }

    return canStepLightbox(state.index, 1, state.attachments.length);
  });

  readonly lightboxPositionLabel = computed(() => {
    const state = this.lightboxState();

    if (!state || state.attachments.length <= 1) {
      return '';
    }

    return `${state.index + 1} / ${state.attachments.length}`;
  });

  private readonly appI18n = inject(AppI18nService);
  private readonly LIGHTBOX_CONTROLS_IDLE_MS = 2200;

  private lightboxControlsHideTimer: ReturnType<typeof setTimeout> | null = null;

  private readonly syncLightboxControls = effect(() => {
    if (this.lightboxState()) {
      this.revealLightboxControlsTemporarily();
      return;
    }

    this.clearLightboxControlsHideTimer();
    this.lightboxControlsVisible.set(true);
  });

  @HostListener('document:mousemove')
  onDocumentMouseMove(): void {
    if (!this.lightboxState()) {
      return;
    }

    this.revealLightboxControlsTemporarily();
  }

  @HostListener('document:keydown.escape')
  onEscapePressed(): void {
    if (this.lightboxState()) {
      this.closeLightbox();
      return;
    }

    if (this.galleryAttachments()) {
      this.closeGallery();
    }
  }

  @HostListener('document:keydown.arrowleft')
  onArrowLeftPressed(): void {
    if (!this.lightboxState()) {
      return;
    }

    this.showPreviousLightboxImage();
  }

  @HostListener('document:keydown.arrowright')
  onArrowRightPressed(): void {
    if (!this.lightboxState()) {
      return;
    }

    this.showNextLightboxImage();
  }

  closeLightbox(): void {
    this.lightboxClosed.emit();
  }

  closeGallery(): void {
    this.galleryClosed.emit();
  }

  showPreviousLightboxImage(): void {
    if (!this.canShowPreviousLightboxImage()) {
      return;
    }

    this.lightboxStepRequested.emit(-1);
  }

  showNextLightboxImage(): void {
    if (!this.canShowNextLightboxImage()) {
      return;
    }

    this.lightboxStepRequested.emit(1);
  }

  openGalleryImage(attachment: Attachment): void {
    const attachments = this.galleryAttachments()?.filter((entry) => entry.available && entry.objectUrl) ?? [];

    if (!attachment.available || !attachment.objectUrl || attachments.length === 0) {
      return;
    }

    this.imageOpened.emit({
      attachment,
      attachments
    });
  }

  closeImageContextMenu(): void {
    this.contextMenuClosed.emit();
  }

  downloadAttachment(attachment: Attachment): void {
    this.downloadRequested.emit(attachment);
  }

  copyImageToClipboard(attachment: Attachment): void {
    this.copyRequested.emit(attachment);
  }

  openImageContextMenu(event: MouseEvent, attachment: Attachment): void {
    event.preventDefault();
    event.stopPropagation();
    this.imageContextMenuRequested.emit({
      positionX: event.clientX,
      positionY: event.clientY,
      attachment
    });
  }

  formatBytes(bytes: number): string {
    const unitKeys = [
      'chat.units.b',
      'chat.units.kb',
      'chat.units.mb',
      'chat.units.gb'
    ];

    let size = bytes;
    let unitIndex = 0;

    while (size >= 1024 && unitIndex < unitKeys.length - 1) {
      size /= 1024;
      unitIndex++;
    }

    return `${size.toFixed(1)} ${this.appI18n.instant(unitKeys[unitIndex])}`;
  }

  openImageAriaLabel(filename: string): string {
    return this.appI18n.instant('chat.overlays.openImage', { filename });
  }

  ngOnDestroy(): void {
    this.clearLightboxControlsHideTimer();
  }

  private revealLightboxControlsTemporarily(): void {
    this.lightboxControlsVisible.set(true);
    this.clearLightboxControlsHideTimer();
    this.lightboxControlsHideTimer = setTimeout(() => {
      this.lightboxControlsHideTimer = null;
      this.lightboxControlsVisible.set(false);
    }, this.LIGHTBOX_CONTROLS_IDLE_MS);
  }

  private clearLightboxControlsHideTimer(): void {
    if (this.lightboxControlsHideTimer) {
      clearTimeout(this.lightboxControlsHideTimer);
      this.lightboxControlsHideTimer = null;
    }
  }
}
