import type { NewProductImage, ProductImage, ProductImageOrderItem } from './image.js';
import type { NewProduct, Product, ProductPatch, ProductSearchCriteria } from './product.js';
import type {
  NewProductVariant,
  ProductRichData,
  ProductVariant,
  ProductVariantPatch,
  RichDataPatch,
} from './variant.js';

export interface ProductRepository {
  findById(id: string): Promise<Product | undefined>;
  findActiveBySlug(slug: string): Promise<Product | undefined>;
  create(input: NewProduct): Promise<Product>;
  update(id: string, patch: ProductPatch): Promise<Product | undefined>;
  delete(id: string): Promise<void>;
  listAll(options?: {
    limit?: number;
    offset?: number;
    q?: string;
  }): Promise<{ items: Product[]; total: number }>;
  categoriesExist(categoryIds: readonly string[]): Promise<boolean>;
  brandExists(brandId: string): Promise<boolean>;
}

export interface ProductSearchRepository {
  search(input: ProductSearchCriteria): Promise<Product[]>;
  /**
   * Returns suggested term corrections using trigram similarity.
   * Falls back to brand/category names when no products match.
   */
  suggestCorrections(term: string): Promise<string[]>;
}

export interface ProductVariantRepository {
  listByProductId(productId: string): Promise<ProductVariant[]>;
  create(productId: string, input: NewProductVariant): Promise<ProductVariant>;
  update(
    productId: string,
    variantId: string,
    patch: ProductVariantPatch,
  ): Promise<ProductVariant | undefined>;
}

export interface ProductRichDataRepository {
  findByProductId(productId: string): Promise<ProductRichData | undefined>;
  upsert(productId: string, patch: RichDataPatch): Promise<ProductRichData>;
}

export interface ProductImageRepository {
  listByProductId(productId: string, variantId?: string | null): Promise<ProductImage[]>;
  /**
   * Fetch images for many products in a single query. Returns a flat array;
   * the caller groups by productId when needed.
   */
  listByProductIds(productIds: readonly string[]): Promise<ProductImage[]>;
  attach(productId: string, input: NewProductImage): Promise<ProductImage>;
  detach(productId: string, imageId: string): Promise<boolean>;
  reorder(productId: string, items: readonly ProductImageOrderItem[]): Promise<ProductImage[]>;
  variantBelongsToProduct(productId: string, variantId: string): Promise<boolean>;
}
