import { Category, Product, SortOption } from '@/domain/entities';

export type CategoryFilter = Category | 'all';

export interface FilterProductsInput {
  products: Product[];
  category: CategoryFilter;
  searchQuery: string;
  sortBy: SortOption;
  /** Resolved display names for search (application layer provides these) */
  searchIndex?: Array<{
    product: Product;
    name: string;
    description: string;
  }>;
}

/**
 * DOMAIN SERVICE — Catalog filtering and sorting rules
 */
export class CatalogDomainService {
  static readonly CATEGORIES: Category[] = ['chicken', 'beef', 'lamb', 'fish'];

  static parseCategory(value: string | null): CategoryFilter {
    return CatalogDomainService.CATEGORIES.includes(value as Category)
      ? (value as Category)
      : 'all';
  }

  static filterAndSort(input: FilterProductsInput): Product[] {
    let result = [...input.products];

    if (input.category !== 'all') {
      result = result.filter((p) => p.category === input.category);
    }

    const query = input.searchQuery.trim().toLowerCase();
    if (query && input.searchIndex) {
      const matchingIds = new Set(
        input.searchIndex
          .filter(
            (entry) =>
              entry.name.toLowerCase().includes(query) ||
              entry.description.toLowerCase().includes(query) ||
              entry.product.tags.some((tag) => tag.includes(query))
          )
          .map((entry) => entry.product.id)
      );
      result = result.filter((p) => matchingIds.has(p.id));
    }

    switch (input.sortBy) {
      case 'price-asc':
        result.sort((a, b) => a.price - b.price);
        break;
      case 'price-desc':
        result.sort((a, b) => b.price - a.price);
        break;
      case 'name':
        if (input.searchIndex) {
          const nameMap = new Map(
            input.searchIndex.map((e) => [e.product.id, e.name])
          );
          result.sort((a, b) =>
            (nameMap.get(a.id) ?? '').localeCompare(nameMap.get(b.id) ?? '')
          );
        }
        break;
      case 'featured':
      default:
        result.sort((a, b) => (b.featured ? 1 : 0) - (a.featured ? 1 : 0));
        break;
    }

    return result;
  }
}