import { Injectable, computed, inject, signal } from '@angular/core';
import { Product } from '../../core/products/models/product-domain.model';
import { ComparedProduct, ContinueBrowsingState, FavoriteItem, RecentlyViewedItem, SavedSearch } from '../../core/user-experience/models/user-experience.model';
import { USER_EXPERIENCE_REPOSITORY } from '../../core/user-experience/user-experience-repository.token';

@Injectable({ providedIn: 'root' })
export class UserExperienceFacade {
  private readonly repository = inject(USER_EXPERIENCE_REPOSITORY);

  private readonly wishlistState = signal<FavoriteItem[]>(this.repository.getWishlist());
  private readonly compareState = signal<ComparedProduct[]>(this.repository.getComparedProducts());
  private readonly recentlyViewedState = signal<RecentlyViewedItem[]>(this.repository.getRecentlyViewed());
  private readonly savedSearchesState = signal<SavedSearch[]>(this.repository.getSavedSearches());

  readonly wishlist = this.wishlistState.asReadonly();
  readonly comparedProducts = this.compareState.asReadonly();
  readonly recentlyViewed = this.recentlyViewedState.asReadonly();
  readonly savedSearches = this.savedSearchesState.asReadonly();

  readonly wishlistCount = computed(() => this.wishlistState().length);
  readonly compareCount = computed(() => this.compareState().length);

  isInWishlist(productId: number): boolean {
    return this.wishlistState().some(item => item.product.itemID === productId);
  }

  isInCompare(productId: number): boolean {
    return this.compareState().some(item => item.product.itemID === productId);
  }

  toggleWishlist(product: Product, ownerType: FavoriteItem['ownerType'] = 'guest'): { added: boolean; count: number } {
    const existing = this.wishlistState();
    const present = existing.some(item => item.product.itemID === product.itemID);

    const next = present
      ? existing.filter(item => item.product.itemID !== product.itemID)
      : [{ product, addedAt: new Date().toISOString(), ownerType }, ...existing];

    this.wishlistState.set(next);
    this.repository.saveWishlist(next);

    return { added: !present, count: next.length };
  }

  clearWishlist(): void {
    this.wishlistState.set([]);
    this.repository.saveWishlist([]);
  }

  addToCompare(product: Product, maxItems: number): { added: boolean; reason?: 'limit'; count: number } {
    const existing = this.compareState();

    if (existing.some(item => item.product.itemID === product.itemID)) {
      return { added: false, count: existing.length };
    }

    if (existing.length >= maxItems) {
      return { added: false, reason: 'limit', count: existing.length };
    }

    const next = [{ product, addedAt: new Date().toISOString() }, ...existing];
    this.compareState.set(next);
    this.repository.saveComparedProducts(next);

    return { added: true, count: next.length };
  }

  removeFromCompare(productId: number): void {
    const next = this.compareState().filter(item => item.product.itemID !== productId);
    this.compareState.set(next);
    this.repository.saveComparedProducts(next);
  }

  clearCompare(): void {
    this.compareState.set([]);
    this.repository.saveComparedProducts([]);
  }

  trackRecentlyViewed(product: Product, maxItems: number): void {
    const existing = this.recentlyViewedState().filter(item => item.product.itemID !== product.itemID);
    const next = [{ product, viewedAt: new Date().toISOString() }, ...existing].slice(0, Math.max(1, maxItems));

    this.recentlyViewedState.set(next);
    this.repository.saveRecentlyViewed(next);
  }

  clearRecentlyViewed(): void {
    this.recentlyViewedState.set([]);
    this.repository.saveRecentlyViewed([]);
  }

  saveSearch(input: Omit<SavedSearch, 'id' | 'createdAt'>, maxItems: number): SavedSearch {
    const normalizedQuery = input.query.trim();
    const existing = this.savedSearchesState();
    const duplicateIndex = existing.findIndex(entry =>
      entry.query.toLowerCase() === normalizedQuery.toLowerCase() &&
      entry.sort === input.sort &&
      (entry.categoryId ?? null) === (input.categoryId ?? null)
    );

    if (duplicateIndex >= 0) {
      return existing[duplicateIndex];
    }

    const nextEntry: SavedSearch = {
      ...input,
      query: normalizedQuery,
      id: `saved-search-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
      createdAt: new Date().toISOString()
    };

    const next = [nextEntry, ...existing].slice(0, Math.max(1, maxItems));
    this.savedSearchesState.set(next);
    this.repository.saveSavedSearches(next);

    return nextEntry;
  }

  removeSavedSearch(id: string): void {
    const next = this.savedSearchesState().filter(item => item.id !== id);
    this.savedSearchesState.set(next);
    this.repository.saveSavedSearches(next);
  }

  saveContinueBrowsing(state: ContinueBrowsingState): void {
    this.repository.saveContinueBrowsing(state);
  }

  getContinueBrowsing(routeKey: string): ContinueBrowsingState | null {
    return this.repository.getContinueBrowsing(routeKey);
  }

  clearContinueBrowsing(routeKey: string): void {
    this.repository.clearContinueBrowsing(routeKey);
  }
}
