import type {
  BrowserFetcher,
  OfferCache,
  OfferRefreshRequest,
  OfferRefreshResponse,
  PoliteFetcher,
  StoreInfo,
  StoreSearchResponse,
} from "./core/types.js";
import { normalizeQuery } from "./core/normalize.js";
import { enabledAdapters, getAdapter } from "./core/registry.js";
import { SearchService } from "./core/search.js";
import { refreshOffer as runOfferRefresh } from "./core/offerRefresh.js";
import { validateOutUrl } from "./core/redirect.js";

export interface EngineDependencies {
  http: PoliteFetcher;
  browser: BrowserFetcher;
  cache: OfferCache;
}

export class EngineRequestError extends Error {
  readonly statusCode: 400 | 404;

  constructor(
    public readonly code: "unknown_store" | "invalid_query" | "invalid_product_url",
    message: string,
  ) {
    super(message);
    this.name = "EngineRequestError";
    this.statusCode = code === "unknown_store" ? 404 : 400;
  }
}

export function createEngine({ http, browser, cache }: EngineDependencies) {
  const ctx = { http, browser };
  const service = new SearchService(ctx, cache);

  return {
    stores(): { stores: StoreInfo[] } {
      return {
        stores: enabledAdapters().map((adapter) => ({
          id: adapter.id,
          displayName: adapter.displayName,
          homepage: adapter.storeHomepage,
          fetchMode: adapter.fetchMode ?? "auto",
        })),
      };
    },

    async search(storeId: string, input: string): Promise<StoreSearchResponse> {
      const adapter = getAdapter(storeId);
      if (!adapter || !adapter.enabled) {
        throw new EngineRequestError("unknown_store", "unknown store");
      }
      const query = normalizeQuery(input);
      if (!query) throw new EngineRequestError("invalid_query", "invalid query");
      const outcome = await service.search(adapter, query);
      return {
        store: adapter.id,
        displayName: adapter.displayName,
        query: query.canonical,
        ...outcome,
      };
    },

    async refreshOffer(request: OfferRefreshRequest): Promise<OfferRefreshResponse> {
      const adapter = getAdapter(request.store);
      if (!adapter || !adapter.enabled) {
        throw new EngineRequestError("unknown_store", "unknown store");
      }
      const url = validateOutUrl(adapter, request.url);
      if (!url) throw new EngineRequestError("invalid_product_url", "invalid product URL");
      return runOfferRefresh(adapter, { ...request, url }, ctx);
    },

    /** Operational counters remain available to the POC health route. */
    counters: service.counters,
  };
}

export type Engine = ReturnType<typeof createEngine>;
