import { Injectable, inject } from '@angular/core';
import { BatchingResource } from '@isa/common/data-access';
import { RemissionStockService } from '../services';
import { FetchStockInStock } from '../schemas';
import { StockInfo } from '../models';

export type StockInfoResourceParams = { itemId: number } & (
  | { stockId?: number }
  | { branchId: number }
);

/**
 * Smart batching resource for stock information.
 * Collects item params from multiple components, waits for a batching window,
 * then makes a single API request with all items to minimize network calls.
 *
 * @example
 * // In a component
 * const stockInfoResource = inject(StockInfoResource);
 * const stockInfo = stockInfoResource.resource({ itemId: 123, stockId: 456 });
 *
 * // Access the stock info
 * const inStock = computed(() => stockInfo.value()?.inStock ?? 0);
 */
@Injectable({ providedIn: 'root' })
export class StockInfoResource extends BatchingResource<
  StockInfoResourceParams,
  FetchStockInStock,
  StockInfo
> {
  #stockService = inject(RemissionStockService);
  #currentBatchBranchId?: number;

  constructor() {
    super(250); // batchWindowMs
  }

  /**
   * Fetch stock information for multiple items.
   */
  protected fetchFn(
    params: FetchStockInStock,
    signal: AbortSignal,
  ): Promise<StockInfo[]> {
    return this.#stockService.fetchStockInfos(params, signal);
  }

  /**
   * Build API request params from list of item params.
   */
  protected buildParams(
    paramsList: { itemId: number; stockId?: number; branchId?: number }[],
  ): FetchStockInStock {
    const first = paramsList[0];
    // Track branchId for result matching (StockInfo doesn't contain branchId)
    this.#currentBatchBranchId = first?.branchId;

    if (first?.branchId !== undefined) {
      return {
        itemIds: paramsList.map((p) => p.itemId),
        branchId: first.branchId,
      };
    }
    return {
      itemIds: paramsList.map((p) => p.itemId),
      stockId: first?.stockId,
    };
  }

  /**
   * Extract params from result for cache matching.
   * Uses tracked branchId since StockInfo doesn't contain it.
   */
  protected getKeyFromResult(
    stock: StockInfo,
  ): { itemId: number; stockId?: number; branchId?: number } | undefined {
    if (stock.itemId === undefined) {
      return undefined;
    }
    return {
      itemId: stock.itemId,
      branchId: this.#currentBatchBranchId,
    };
  }

  /**
   * Generate cache key from params.
   */
  protected getCacheKey(params: {
    itemId: number;
    stockId?: number;
    branchId?: number;
  }): string {
    if (params.branchId !== undefined) {
      return `branch-${params.branchId}-${params.itemId}`;
    }
    return `${params.stockId ?? 'default'}-${params.itemId}`;
  }

  /**
   * Extract params from resource params for status tracking.
   * Required by BatchingResource base class.
   */
  protected extractKeysFromParams(
    params: FetchStockInStock,
  ): { itemId: number; stockId?: number }[] {
    return params.itemIds.map((itemId) => ({
      itemId,
      stockId: 'stockId' in params ? params.stockId : undefined,
      branchId: 'branchId' in params ? params.branchId : undefined,
    }));
  }

  /**
   * Reloads specific items by removing them from cache.
   * Convenience method that accepts item IDs instead of full params.
   *
   * @param itemIds - Array of item IDs to reload
   * @returns Promise that resolves when reload completes
   *
   * @example
   * stockInfoResource.reloadItems([123, 456, 789]);
   */
  reloadItems(itemIds: number[]) {
    // Convert itemIds to params (stockId will be undefined, matching all stockIds)
    const paramsToReload = itemIds.flatMap((itemId) => [
      { itemId, stockId: undefined },
      { itemId }, // stockId undefined variant
    ]);
    return this.reloadKeys(paramsToReload);
  }
}
