/* eslint-disable @typescript-eslint/member-ordering */
import {
  Component,
  computed,
  effect,
  inject,
  OnDestroy
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideMessageCircle, lucideTrash2 } from '@ng-icons/lucide';
import { map } from 'rxjs';
import { UserAvatarComponent } from '../../../../shared';
import { ThemeNodeDirective, ThemeService } from '../../../theme';
import { AttachmentFacade } from '../../../attachment';
import { VoiceControlsComponent } from '../../../voice-session';
import { DirectMessageService } from '../../application/services/direct-message.service';
import { DmChatComponent } from '../dm-chat/dm-chat.component';
import { selectAllUsers } from '../../../../store/users/users.selectors';
import type { DirectMessageConversation } from '../../domain/models/direct-message.model';
import type { Attachment } from '../../../attachment';
import type { User } from '../../../../shared-kernel';

@Component({
  selector: 'app-dm-workspace',
  standalone: true,
  imports: [
    CommonModule,
    NgIcon,
    UserAvatarComponent,
    ThemeNodeDirective,
    DmChatComponent,
    VoiceControlsComponent
  ],
  viewProviders: [provideIcons({ lucideMessageCircle, lucideTrash2 })],
  templateUrl: './dm-workspace.component.html'
})
export class DmWorkspaceComponent implements OnDestroy {
  private readonly route = inject(ActivatedRoute);
  private readonly router = inject(Router);
  private readonly theme = inject(ThemeService);
  private readonly store = inject(Store);
  private readonly attachments = inject(AttachmentFacade);

  readonly directMessages = inject(DirectMessageService);
  readonly users = this.store.selectSignal(selectAllUsers);
  readonly routeConversationId = toSignal(this.route.paramMap.pipe(map((params) => params.get('conversationId'))), {
    initialValue: this.route.snapshot.paramMap.get('conversationId')
  });
  readonly layoutStyles = computed(() => this.theme.getLayoutContainerStyles('dmLayout'));
  readonly listPanelStyles = computed(() => this.theme.getLayoutItemStyles('dmConversationsPanel'));
  readonly chatPanelStyles = computed(() => this.theme.getLayoutItemStyles('dmChatPanel'));

  constructor() {
    effect(() => {
      const conversationId = this.routeConversationId();

      if (conversationId) {
        void this.directMessages.openConversation(conversationId);
        return;
      }

      const firstConversation = this.directMessages.conversations()[0];

      if (firstConversation) {
        void this.router.navigate(['/dm', firstConversation.id], { replaceUrl: true });
      }
    });

    effect(() => {
      const users = this.users();

      for (const conversation of this.directMessages.conversations()) {
        const peer = this.peerUser(conversation, users);

        if (!peer?.avatarUrl) {
          this.directMessages.requestPeerAvatarSync(conversation.id);
        }
      }
    });
  }

  openConversation(conversation: DirectMessageConversation): void {
    void this.router.navigate(['/dm', conversation.id]);
  }

  ngOnDestroy(): void {
    this.directMessages.closeConversationView(this.routeConversationId());
  }

  isSelectedConversation(conversation: DirectMessageConversation): boolean {
    return this.routeConversationId() === conversation.id;
  }

  peerName(conversation: DirectMessageConversation): string {
    const peerId = this.peerId(conversation);
    const knownUser = this.peerUser(conversation);

    return peerId ? knownUser?.displayName || conversation.participantProfiles[peerId]?.displayName || peerId : 'Direct Message';
  }

  peerAvatarUrl(conversation: DirectMessageConversation): string | undefined {
    const peerId = this.peerId(conversation);
    const knownUser = this.peerUser(conversation);

    return peerId ? knownUser?.avatarUrl || conversation.participantProfiles[peerId]?.avatarUrl : undefined;
  }

  lastMessagePreview(conversation: DirectMessageConversation): string {
    const lastMessage = conversation.messages.at(-1);

    if (!lastMessage) {
      return 'No messages yet';
    }

    if (lastMessage.isDeleted) {
      return 'Message deleted';
    }

    if (this.isKlipyGif(lastMessage.content)) {
      return 'Sent a GIF';
    }

    this.attachments.updated();
    const attachments = this.attachments.getForMessage(lastMessage.id);

    if (attachments.length > 0) {
      return this.attachmentPreview(attachments);
    }

    return lastMessage.content || 'Attachment';
  }

  async forgetConversation(event: Event, conversation: DirectMessageConversation): Promise<void> {
    event.stopPropagation();
    const conversations = this.directMessages.conversations();
    const nextConversation = conversations.find((entry) => entry.id !== conversation.id) ?? null;

    await this.directMessages.forgetConversation(conversation.id);

    if (this.routeConversationId() === conversation.id) {
      await this.router.navigate(nextConversation ? ['/dm', nextConversation.id] : ['/dm']);
    }
  }

  formatUnreadCount(count: number): string {
    return count > 99 ? '99+' : String(count);
  }

  private peerId(conversation: DirectMessageConversation): string | undefined {
    const currentUserId = this.directMessages.currentUserId();

    return conversation.participants.find((participantId) => participantId !== currentUserId);
  }

  private peerUser(conversation: DirectMessageConversation, users = this.users()): User | undefined {
    const peerId = this.peerId(conversation);

    return peerId ? users.find((user) => user.id === peerId || user.oderId === peerId) : undefined;
  }

  private isKlipyGif(content: string): boolean {
    return /!\[KLIPY GIF\]\([^)]*static\.klipy\.com[^)]*\)/i.test(content.trim());
  }

  private attachmentPreview(attachments: Attachment[]): string {
    if (attachments.some((attachment) => attachment.mime.startsWith('image/'))) {
      return 'Sent an image';
    }

    if (attachments.some((attachment) => attachment.mime.startsWith('video/'))) {
      return 'Sent a video';
    }

    if (attachments.some((attachment) => attachment.mime.startsWith('audio/'))) {
      return 'Sent audio';
    }

    return attachments.length === 1 ? 'Sent an attachment' : 'Sent attachments';
  }
}
