import { Injectable, Logger } from '@nestjs/common';
import { createHash } from 'crypto';
import { envs } from 'src/config';
import { RedisService } from 'src/redis/redis.service';
import type { ResultadoSerper } from './pipeline/tipos';

export const SERPER_RESULTADOS_POR_QUERY = 10;
/** cache-manager usa milisegundos. */
export const SERPER_CACHE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
const SERPER_URL = 'https://google.serper.dev/images';
const INTENTOS = 3;

/**
 * Google Images vía Serper.dev con key de plataforma. Cachea cada query en Redis
 * 30 días: relanzar una búsqueda o repetir productos entre empresas no vuelve a pagar.
 */
@Injectable()
export class BuscadorSerperService {
  private readonly logger = new Logger(BuscadorSerperService.name);
  /** Sobreescribibles en tests (Nest solo inyecta RedisService). */
  fetchFn: typeof fetch = fetch;
  esperaReintentoMs = 1500;

  constructor(private readonly redis: RedisService) {}

  disponible(): boolean {
    return !!envs.serperApiKey;
  }

  async buscar(query: string): Promise<{ resultados: ResultadoSerper[]; desdeCache: boolean }> {
    const clave = `imgia:serper:${createHash('sha1').update(query.trim().toLowerCase()).digest('hex')}`;
    const cache = await this.redis.get<ResultadoSerper[]>(clave);
    if (cache) return { resultados: cache, desdeCache: true };

    const resultados = await this.consultar(query);
    await this.redis.set(clave, resultados, SERPER_CACHE_TTL_MS);
    return { resultados, desdeCache: false };
  }

  private async consultar(query: string): Promise<ResultadoSerper[]> {
    let ultimoError = '';
    for (let intento = 1; intento <= INTENTOS; intento++) {
      const res = await this.fetchFn(SERPER_URL, {
        method: 'POST',
        headers: { 'X-API-KEY': envs.serperApiKey ?? '', 'Content-Type': 'application/json' },
        body: JSON.stringify({ q: query, gl: 'py', hl: 'es', num: SERPER_RESULTADOS_POR_QUERY }),
      });
      if (res.ok) {
        const data = (await res.json()) as { images?: Array<Record<string, unknown>> };
        return (data.images ?? [])
          .filter((i) => typeof i.imageUrl === 'string')
          .map((i) => ({
            imageUrl: i.imageUrl as string,
            title: (i.title as string) ?? '',
            domain: (i.domain as string) ?? '',
            imageWidth: Number(i.imageWidth) || 0,
            imageHeight: Number(i.imageHeight) || 0,
          }));
      }
      ultimoError = `Serper ${res.status}: ${(await res.text()).slice(0, 200)}`;
      const reintentable = res.status === 429 || res.status >= 500;
      if (!reintentable || intento === INTENTOS) break;
      this.logger.warn(`${ultimoError} — reintento ${intento}/${INTENTOS - 1}`);
      await new Promise((r) => setTimeout(r, this.esperaReintentoMs * intento));
    }
    throw new Error(ultimoError);
  }
}
