/* eslint-disable @typescript-eslint/member-ordering */
import { CommonModule } from '@angular/common';
import {
  Component,
  ElementRef,
  HostListener,
  computed,
  effect,
  inject,
  input,
  output,
  signal
} from '@angular/core';
import { NgIcon, provideIcons } from '@ng-icons/core';
import {
  lucidePlus,
  lucideSearch,
  lucideSmile,
  lucideUpload,
  lucideX
} from '@ng-icons/lucide';
import { CustomEmoji, EmojiShortcutEntry } from '../../../../shared-kernel';
import { CustomEmojiService } from '../../application/custom-emoji.service';
import { APP_TRANSLATE_IMPORTS, AppI18nService } from '../../../../core/i18n';
import { AutoFocusDirective, SelectOnFocusDirective } from '../../../../shared/directives';
import {
  CUSTOM_EMOJI_ACCEPT_ATTRIBUTE,
  UNICODE_EMOJI_PICKER_ENTRIES,
  buildCustomEmojiMessageToken,
  filterCustomEmojisForPicker,
  filterUnicodeEmojiPickerEntries,
  normalizeEmojiPickerSearchQuery
} from '../../domain/custom-emoji.rules';

@Component({
  selector: 'app-custom-emoji-picker',
  standalone: true,
  imports: [
    CommonModule,
    NgIcon,
    AutoFocusDirective,
    SelectOnFocusDirective,
    ...APP_TRANSLATE_IMPORTS
  ],
  viewProviders: [provideIcons({ lucidePlus, lucideSearch, lucideSmile, lucideUpload, lucideX })],
  templateUrl: './custom-emoji-picker.component.html'
})
export class CustomEmojiPickerComponent {
  private readonly customEmoji = inject(CustomEmojiService);
  private readonly appI18n = inject(AppI18nService);
  private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);

  readonly currentUserId = input<string | null>(null);
  readonly compact = input(true);
  /** Render the picker panel in normal document flow for bottom-sheet embedding. */
  readonly inline = input(false);

  readonly emojiSelected = output<string>();
  readonly dismissed = output();

  readonly acceptAttribute = CUSTOM_EMOJI_ACCEPT_ATTRIBUTE;
  readonly modalOpen = signal(false);
  readonly uploadError = signal<string | null>(null);
  readonly uploading = signal(false);
  readonly shortcuts = this.customEmoji.shortcutEntries;
  readonly customEmojis = this.customEmoji.emojis;
  readonly searchQuery = signal('');
  readonly filteredUnicodeEntries = computed(() => filterUnicodeEmojiPickerEntries(
    UNICODE_EMOJI_PICKER_ENTRIES,
    this.searchQuery()
  ));
  readonly filteredCustomEmojis = computed(() => filterCustomEmojisForPicker(
    this.customEmojis(),
    this.searchQuery()
  ));
  readonly hasActiveSearch = computed(() => normalizeEmojiPickerSearchQuery(this.searchQuery()).length > 0);
  readonly showEmptySearchState = computed(() => this.hasActiveSearch()
    && this.filteredUnicodeEntries().length === 0
    && this.filteredCustomEmojis().length === 0);
  private readonly loadForUser = effect(() => {
    void this.customEmoji.loadForUser(this.currentUserId());
  });

  setSearchQuery(query: string): void {
    this.searchQuery.set(query);
  }

  onSearchInput(event: Event): void {
    this.setSearchQuery((event.target as HTMLInputElement).value);
  }

  selectShortcut(entry: EmojiShortcutEntry): void {
    this.customEmoji.recordUsage(entry, this.currentUserId());
    this.emojiSelected.emit(entry.kind === 'custom' ? buildCustomEmojiMessageToken(entry.emoji) : entry.emoji);
  }

  selectUnicode(emoji: string): void {
    this.customEmoji.recordUsage({ kind: 'unicode',
      key: `unicode:${emoji}`,
      emoji,
      label: emoji }, this.currentUserId());

    this.emojiSelected.emit(emoji);
    this.modalOpen.set(false);
  }

  selectCustom(emoji: CustomEmoji): void {
    this.customEmoji.recordUsage({ kind: 'custom',
      key: `custom:${emoji.id}`,
      emoji,
      label: emoji.name }, this.currentUserId());

    this.emojiSelected.emit(buildCustomEmojiMessageToken(emoji));
    this.modalOpen.set(false);
  }

  @HostListener('document:click', ['$event'])
  onDocumentClick(event: MouseEvent): void {
    const target = event.target;

    if (target == null || this.host.nativeElement.contains(target as Node)) {
      return;
    }

    this.dismiss();
  }

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

  openModal(): void {
    this.modalOpen.set(true);
  }

  closeModal(): void {
    this.dismiss();
  }

  dismiss(): void {
    this.modalOpen.set(false);
    this.searchQuery.set('');
    this.dismissed.emit();
  }

  async uploadEmoji(event: Event): Promise<void> {
    const inputElement = event.target as HTMLInputElement;
    const file = inputElement.files?.[0];
    const userId = this.currentUserId();

    inputElement.value = '';

    if (!file || !userId) {
      return;
    }

    this.uploadError.set(null);
    this.uploading.set(true);

    try {
      const emoji = await this.customEmoji.createFromFile(file, userId);

      this.selectCustom(emoji);
    } catch (error) {
      this.uploadError.set(error instanceof Error ? error.message : this.appI18n.instant('emoji.picker.uploadFailed'));
    } finally {
      this.uploading.set(false);
    }
  }
}
