/**
 * @copyright 2026 NHCarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */

import { Injectable, inject, signal, computed } from '@angular/core';
import { Observable, map, tap, catchError, of } from 'rxjs';
import { ApiService } from './api.service';
import { CreateLikeDto, LikeResponse, LikedItemDto, Like } from '@library/shared-types';

interface LikeState {
  entityType: Like['entityType'];
  entityId: string;
  liked: boolean;
  count: number;
}

@Injectable({
  providedIn: 'root'
})
export class LikesService {
  private api = inject(ApiService);

  // Store like states for caching
  private likeStates = signal<Map<string, LikeState>>(new Map());

  /**
   * Toggle like on an item.
   */
  toggleLike(entityType: Like['entityType'], entityId: string): Observable<LikeResponse> {
    const dto: CreateLikeDto = { entityType, entityId };

    return this.api.post<LikeResponse>('/likes/toggle', dto).pipe(
      tap(response => {
        const key = this.getCacheKey(entityType, entityId);
        this.likeStates.update(states => {
          const newStates = new Map(states);
          newStates.set(key, {
            entityType,
            entityId,
            liked: response.liked,
            count: response.count
          });
          return newStates;
        });
      }),
      catchError(() => {
        // On error, return current state or default
        const key = this.getCacheKey(entityType, entityId);
        const currentState = this.likeStates().get(key);
        return of({
          liked: currentState?.liked || false,
          count: currentState?.count || 0
        });
      })
    );
  }

  /**
   * Get like count for an item.
   */
  getLikeCount(entityType: Like['entityType'], entityId: string): Observable<number> {
    return this.api.get<{ count: number }>(`/likes/count?entityType=${entityType}&entityId=${entityId}`).pipe(
      map(response => response.count),
      tap(count => {
        const key = this.getCacheKey(entityType, entityId);
        this.likeStates.update(states => {
          const newStates = new Map(states);
          const currentState = newStates.get(key);
          newStates.set(key, {
            entityType,
            entityId,
            liked: currentState?.liked || false,
            count
          });
          return newStates;
        });
      })
    );
  }

  /**
   * Check if current user has liked an item.
   */
  getUserLikeStatus(entityType: Like['entityType'], entityId: string): Observable<boolean> {
    return this.api.get<{ liked: boolean }>(`/likes/status?entityType=${entityType}&entityId=${entityId}`).pipe(
      map(response => response.liked),
      tap(liked => {
        const key = this.getCacheKey(entityType, entityId);
        this.likeStates.update(states => {
          const newStates = new Map(states);
          const currentState = newStates.get(key);
          newStates.set(key, {
            entityType,
            entityId,
            liked,
            count: currentState?.count || 0
          });
          return newStates;
        });
      })
    );
  }

  /**
   * Get all items liked by the current user.
   */
  getUserLikedItems(entityType?: Like['entityType']): Observable<LikedItemDto[]> {
    const query = entityType ? `?entityType=${entityType}` : '';
    return this.api.get<LikedItemDto[]>(`/likes/user${query}`);
  }

  /**
   * Get bulk like statuses for multiple items.
   */
  getBulkLikeStatuses(items: Array<{ entityType: string; entityId: string }>): Observable<Array<{
    entityType: string;
    entityId: string;
    liked: boolean;
    count: number;
  }>> {
    return this.api.post<Array<{
      entityType: string;
      entityId: string;
      liked: boolean;
      count: number;
    }>>('/likes/bulk-status', { items }).pipe(
      tap(results => {
        this.likeStates.update(states => {
          const newStates = new Map(states);
          results.forEach(result => {
            const key = this.getCacheKey(result.entityType as Like['entityType'], result.entityId);
            newStates.set(key, {
              entityType: result.entityType as Like['entityType'],
              entityId: result.entityId,
              liked: result.liked,
              count: result.count
            });
          });
          return newStates;
        });
      })
    );
  }

  /**
   * Get like state from cache.
   */
  getCachedLikeState(entityType: Like['entityType'], entityId: string): LikeState | undefined {
    const key = this.getCacheKey(entityType, entityId);
    return this.likeStates().get(key);
  }

  /**
   * Create computed signal for specific item's like state.
   */
  createLikeStateSignal(entityType: Like['entityType'], entityId: string) {
    const key = this.getCacheKey(entityType, entityId);
    return computed(() => {
      const state = this.likeStates().get(key);
      return {
        liked: state?.liked || false,
        count: state?.count || 0
      };
    });
  }

  private getCacheKey(entityType: Like['entityType'], entityId: string): string {
    return `${entityType}:${entityId}`;
  }
}