/* eslint-disable @typescript-eslint/member-ordering */
import {
  Component,
  computed,
  inject,
  input
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
import {
  lucideMessageCircle,
  lucidePhone,
  lucidePhoneCall,
  lucideSearch
} from '@ng-icons/lucide';
import { selectAllUsers, selectCurrentUser } from '../../../../store/users/users.selectors';
import { selectSavedRooms } from '../../../../store/rooms/rooms.selectors';
import { UserAvatarComponent } from '../../../../shared';
import { DirectMessageService } from '../../application/services/direct-message.service';
import { DirectCallService } from '../../../direct-call';
import { FriendService } from '../../application/services/friend.service';
import { FriendButtonComponent } from '../friend-button/friend-button.component';
import type { User } from '../../../../shared-kernel';

@Component({
  selector: 'app-user-search-list',
  standalone: true,
  imports: [
    CommonModule,
    NgIcon,
    UserAvatarComponent,
    FriendButtonComponent
  ],
  viewProviders: [provideIcons({ lucideMessageCircle, lucidePhone, lucidePhoneCall, lucideSearch })],
  templateUrl: './user-search-list.component.html'
})
export class UserSearchListComponent {
  private readonly store = inject(Store);
  private readonly router = inject(Router);
  private readonly directMessages = inject(DirectMessageService);
  readonly directCalls = inject(DirectCallService);
  readonly friends = inject(FriendService);
  readonly searchQuery = input('');
  readonly users = this.store.selectSignal(selectAllUsers);
  readonly savedRooms = this.store.selectSignal(selectSavedRooms);
  readonly currentUser = this.store.selectSignal(selectCurrentUser);
  readonly discoveredUsers = computed(() => {
    const usersById = new Map<string, User>();

    for (const user of this.users()) {
      usersById.set(user.oderId || user.id, user);
    }

    for (const room of this.savedRooms()) {
      for (const member of room.members ?? []) {
        const userId = member.oderId || member.id;

        if (usersById.has(userId)) {
          continue;
        }

        usersById.set(userId, {
          id: member.id,
          oderId: userId,
          username: member.username,
          displayName: member.displayName,
          description: member.description,
          avatarUrl: member.avatarUrl,
          profileUpdatedAt: member.profileUpdatedAt,
          role: member.role,
          joinedAt: member.joinedAt,
          status: 'disconnected'
        });
      }
    }

    return Array.from(usersById.values());
  });
  readonly matchingUsers = computed(() => {
    const query = this.normalizedSearchQuery();
    const currentUserId = this.currentUserKey();

    return this.discoveredUsers()
      .filter((user) => this.userKey(user) !== currentUserId)
      .filter((user) => this.matchesQuery(user, query))
      .slice(0, 24);
  });
  readonly friendResults = computed(() => this.matchingUsers().filter((user) => this.friends.isFriend(this.userKey(user))));
  readonly results = computed(() => {
    const friendIds = this.friends.friendIds();

    return this.matchingUsers().filter((user) => !friendIds.has(this.userKey(user)));
  });

  async messageUser(user: User): Promise<void> {
    const conversation = await this.directMessages.createConversation(user);

    await this.router.navigate(['/dm', conversation.id]);
  }

  async callUser(user: User): Promise<void> {
    await this.directCalls.startCall(user);
  }

  callIcon(user: User): string {
    return this.directCalls.isCallingUser(user) ? 'lucidePhoneCall' : 'lucidePhone';
  }

  userKey(user: User): string {
    return user.oderId || user.id;
  }

  initial(label: string): string {
    return label.trim()[0]?.toUpperCase() || '?';
  }

  private currentUserKey(): string {
    const currentUser = this.currentUser();

    return currentUser ? this.userKey(currentUser) : '';
  }

  private normalizedSearchQuery(): string {
    return this.searchQuery().trim()
      .toLowerCase();
  }

  private matchesQuery(user: User, query: string): boolean {
    if (!query) {
      return true;
    }

    return [
      user.displayName,
      user.username,
      user.description
    ]
      .filter((value): value is string => !!value)
      .some((value) => value.toLowerCase().includes(query));
  }
}
