// Bild-Fallback-Kaskade fuer Restaurant-Karten:
// Stufe 1: OSM image=/wikidata=/wikimedia_commons=-Tags (kostenlos, kein Rate-Limit)
// Stufe 2: manuell vom Admin hinterlegtes Bild (admin_image_url in DB, wird vom Aufrufer bevorzugt)
// Stufe 3: Bilder-Pool pro Kategorie (Pexels-Suche, einmalig pro Kategorie befuellt,
//          Bilder werden dabei LOKAL heruntergeladen und gecacht statt nur die
//          externe Pexels-URL zu speichern - macht uns unabhaengig von Pexels-
//          Rate-Limits/Downtime und die Bilder lassen sich 1:1 fuer die
//          Swipe-Demo auf der Marketing-Landingpage weiterverwenden).
import { getDb } from './db';
import { downloadAndCacheImage } from './image-cache';

interface OsmImageInput {
  imageTag?: string;
  wikidataId?: string;
  wikimediaCommons?: string;
}

async function fetchWithTimeout(url: string, timeoutMs = 6000, options: RequestInit = {}) {
  const controller = new AbortController();
  const id = setTimeout(() => controller.abort(), timeoutMs);
  try {
    return await fetch(url, { ...options, signal: controller.signal });
  } finally {
    clearTimeout(id);
  }
}

// Prueft per HEAD-Request, ob eine Bild-URL tatsaechlich ein Bild liefert (Status
// 200 + Content-Type image/*), BEVOR sie in der DB gespeichert wird. Das war der
// Kern des "broken image"-Problems: OSM image=-Tags zeigen teils auf Wikipedia-
// Artikelseiten statt echte Bilddateien, und solche URLs wurden bisher
// ungeprueft uebernommen. Manche Server unterstuetzen HEAD nicht korrekt und
// antworten mit 405 - in diesem Fall lieber vorsichtig als "gueltig" werten
// (return true), statt faelschlich ein an sich gutes Bild abzulehnen.
async function isImageUrlValid(url: string): Promise<boolean> {
  try {
    const res = await fetchWithTimeout(url, 5000, { method: 'HEAD' });
    if (res.status === 405) return true;
    if (!res.ok) return false;
    const contentType = res.headers.get('content-type') || '';
    return contentType.startsWith('image/');
  } catch {
    return false;
  }
}

function commonsFilenameToUrl(filename: string): string {
  const clean = filename.replace(/^File:/i, '').trim();
  return `https://commons.wikimedia.org/wiki/Special:FilePath/${encodeURIComponent(clean)}?width=800`;
}

// Liefert die erste GUELTIGE Bild-URL aus den OSM-Tags oder null, wenn keine der
// Quellen ein echtes Bild liefert (statt wie bisher die erste vorhandene URL
// ungeprueft durchzuwinken). image_source_used wird vom Aufrufer weiterhin auf
// 'none' gesetzt, wenn hier null zurueckkommt - Stufe 3 (Pexels-Pool) greift
// dann automatisch als naechstes.
export async function resolveOsmImage(input: OsmImageInput): Promise<string | null> {
  const candidates: string[] = [];

  if (input.imageTag) {
    if (input.imageTag.startsWith('http')) candidates.push(input.imageTag);
    else if (input.imageTag.toLowerCase().startsWith('file:')) candidates.push(commonsFilenameToUrl(input.imageTag));
  }
  if (input.wikimediaCommons?.toLowerCase().startsWith('file:')) {
    candidates.push(commonsFilenameToUrl(input.wikimediaCommons));
  }
  if (input.wikidataId) {
    try {
      const res = await fetchWithTimeout(
        `https://www.wikidata.org/wiki/Special:EntityData/${input.wikidataId}.json`,
        5000
      );
      if (res.ok) {
        const data = await res.json();
        const entity = data.entities?.[input.wikidataId];
        const imageClaim = entity?.claims?.P18?.[0]?.mainsnak?.datavalue?.value;
        if (imageClaim) candidates.push(commonsFilenameToUrl(imageClaim));
      }
    } catch {
      // Wikidata nicht erreichbar, evtl. andere Kandidaten trotzdem pruefen
    }
  }

  for (const url of candidates) {
    if (await isImageUrlValid(url)) return url;
  }
  return null;
}

const CUISINE_KEYWORD_MAP: Record<string, string> = {
  ice_cream: 'ice cream dessert',
  cafe: 'coffee cafe',
  coffee_shop: 'coffee cup',
  breakfast: 'breakfast plate',
  bakery: 'bakery bread pastry',
  pizza: 'pizza',
  pasta: 'pasta italian',
  italian: 'italian pasta pizza',
  sushi: 'sushi',
  japanese: 'japanese food',
  burger: 'burger',
  steak_house: 'steak grill',
  seafood: 'seafood plate',
  kebab: 'kebab',
  vegan: 'vegan bowl food',
  vegetarian: 'vegetarian food',
  thai: 'thai food',
  chinese: 'chinese food',
  indian: 'indian curry food',
  mexican: 'mexican tacos food',
  greek: 'greek food',
  turkish: 'turkish food',
};

const POOL_SIZE_PER_CATEGORY = 8;

function pickCategory(cuisine: string | undefined, activeCuisineTags: string[]): string {
  if (!cuisine) return 'restaurant';
  const restaurantTags = cuisine.split(/[,;]/).map((t) => t.trim().toLowerCase()).filter(Boolean);
  if (restaurantTags.length === 0) return 'restaurant';

  const matchingActiveTag = activeCuisineTags.find((tag) => restaurantTags.includes(tag.toLowerCase()));
  return matchingActiveTag || restaurantTags[0];
}

// Befuellt den lokalen Bilder-Pool fuer eine Kategorie einmalig per Pexels-Suche.
// Laedt jedes Treffer-Bild SOFORT lokal herunter (downloadAndCacheImage) und
// speichert den LOKALEN Pfad in image_pool - nicht die Pexels-URL direkt. Bei
// fehlgeschlagenem Download wird dieses eine Bild uebersprungen, der Rest des
// Pools wird trotzdem befuellt.
async function fillPoolForCategory(category: string): Promise<void> {
  const db = getDb();
  const apiKey = process.env.PEXELS_API_KEY;
  if (!apiKey) return;

  const keyword = CUISINE_KEYWORD_MAP[category] || `${category} food`;

  try {
    const res = await fetchWithTimeout(
      `https://api.pexels.com/v1/search?query=${encodeURIComponent(keyword)}&per_page=${POOL_SIZE_PER_CATEGORY}&orientation=portrait`,
      6000,
      { headers: { Authorization: apiKey } }
    );
    if (!res.ok) return;
    const data = await res.json();
    const photos = (data.photos || []) as any[];
    if (photos.length === 0) return;

    const insertStmt = db.prepare(
      'INSERT OR IGNORE INTO image_pool (category, image_url) VALUES (?, ?)'
    );

    for (const photo of photos) {
      const sourceUrl = photo.src?.large as string;
      if (!sourceUrl) continue;
      const localPath = await downloadAndCacheImage(sourceUrl, category);
      if (localPath) {
        insertStmt.run(category, localPath);
      }
    }
  } catch {
    // Pexels nicht erreichbar oder Rate-Limit erreicht -> Pool bleibt ggf. leer,
    // naechster Aufruf versucht es erneut.
  }
}

export async function resolveUnsplashFallback(
  restaurantId: number,
  cuisine?: string,
  activeCuisineTags: string[] = []
): Promise<string | null> {
  const db = getDb();
  const category = pickCategory(cuisine, activeCuisineTags);

  let pool = db.prepare(
    'SELECT image_url FROM image_pool WHERE category = ?'
  ).all(category) as { image_url: string }[];

  if (pool.length === 0) {
    await fillPoolForCategory(category);
    pool = db.prepare(
      'SELECT image_url FROM image_pool WHERE category = ?'
    ).all(category) as { image_url: string }[];
  }

  if (pool.length === 0) return null;

  const randomIndex = Math.floor(Math.random() * pool.length);
  return pool[randomIndex].image_url;
}
