/* eslint-disable @typescript-eslint/member-ordering */
import {
  Injectable,
  computed,
  effect,
  inject,
  signal
} from '@angular/core';
import { Store } from '@ngrx/store';
import { FriendRepository } from '../../infrastructure/friend.repository';
import type { Friend } from '../../domain/models/direct-message.model';
import { selectCurrentUser } from '../../../../store/users/users.selectors';

@Injectable({ providedIn: 'root' })
export class FriendService {
  private readonly repository = inject(FriendRepository);
  private readonly store = inject(Store);
  private readonly currentUser = this.store.selectSignal(selectCurrentUser);
  private readonly friendsSignal = signal<Friend[]>([]);
  private loadedOwnerId: string | null = null;

  readonly friends = this.friendsSignal.asReadonly();
  readonly friendIds = computed(() => new Set(this.friendsSignal().map((friend) => friend.userId)));

  constructor() {
    effect(() => {
      const ownerId = this.currentUser()?.oderId || this.currentUser()?.id || null;

      void this.loadForOwner(ownerId);
    });
  }

  async addFriend(userId: string): Promise<void> {
    const ownerId = await this.requireOwnerId();
    const friend: Friend = { userId, addedAt: Date.now() };

    await this.repository.addFriend(ownerId, friend);
    await this.loadForOwner(ownerId, true);
  }

  async removeFriend(userId: string): Promise<void> {
    const ownerId = await this.requireOwnerId();

    await this.repository.removeFriend(ownerId, userId);
    await this.loadForOwner(ownerId, true);
  }

  isFriend(userId: string): boolean {
    return this.friendIds().has(userId);
  }

  async toggleFriend(userId: string): Promise<void> {
    if (this.isFriend(userId)) {
      await this.removeFriend(userId);
      return;
    }

    await this.addFriend(userId);
  }

  private async loadForOwner(ownerId: string | null, force = false): Promise<void> {
    if (!ownerId) {
      this.loadedOwnerId = null;
      this.friendsSignal.set([]);
      return;
    }

    if (!force && this.loadedOwnerId === ownerId) {
      return;
    }

    this.loadedOwnerId = ownerId;
    this.friendsSignal.set(await this.repository.loadFriends(ownerId));
  }

  private async requireOwnerId(): Promise<string> {
    const ownerId = this.currentUser()?.oderId || this.currentUser()?.id;

    if (!ownerId) {
      throw new Error('Cannot manage friends without a current user.');
    }

    await this.loadForOwner(ownerId);
    return ownerId;
  }
}
