/**
 * Website Image Scraper
 * ─────────────────────
 * Fetches a brand's website pages, extracts images, filters out
 * tracking pixels / icons / ad images, and returns usable images
 * categorized by type. 24-hour cache per domain.
 */

import { prisma } from "@/lib/prisma";

export interface ScrapedImage {
  url: string;
  altText: string;
  width: number | null;
  height: number | null;
  category: "hero" | "product" | "team" | "logo" | "background" | "other";
  sourcePage: string;
}

// Domains to skip (ads, tracking, CDNs we don't want)
const SKIP_DOMAINS = [
  "googleadservices.com", "doubleclick.net", "facebook.com", "fbcdn.net",
  "google-analytics.com", "googletagmanager.com", "analytics", "pixel",
  "track", "beacon", "adservice", "adsystem",
];

const IMG_REGEX = /<img\s[^>]*?>/gi;
const SRC_REGEX = /src=["']([^"']+)["']/i;
const ALT_REGEX = /alt=["']([^"']*?)["']/i;
const WIDTH_REGEX = /width=["']?(\d+)/i;
const HEIGHT_REGEX = /height=["']?(\d+)/i;

// Cache: domain → { images, timestamp }
const cache = new Map<string, { images: ScrapedImage[]; ts: number }>();
const CACHE_TTL = 24 * 3600 * 1000;

function resolveUrl(src: string, baseUrl: string): string | null {
  try {
    return new URL(src, baseUrl).href;
  } catch {
    return null;
  }
}

function isSkippedDomain(url: string): boolean {
  const lower = url.toLowerCase();
  return SKIP_DOMAINS.some((d) => lower.includes(d));
}

function categorize(url: string, alt: string): ScrapedImage["category"] {
  const lower = (url + " " + alt).toLowerCase();
  if (/logo/i.test(lower)) return "logo";
  if (/hero|banner|header|slider|carousel/i.test(lower)) return "hero";
  if (/team|staff|employee|about|founder|ceo/i.test(lower)) return "team";
  if (/product|service|portfolio|work|project/i.test(lower)) return "product";
  if (/bg|background|pattern|texture/i.test(lower)) return "background";
  return "other";
}

function extractImagesFromHtml(html: string, pageUrl: string): ScrapedImage[] {
  const images: ScrapedImage[] = [];
  const matches = html.match(IMG_REGEX) || [];

  for (const tag of matches) {
    const srcMatch = tag.match(SRC_REGEX);
    if (!srcMatch) continue;

    const src = srcMatch[1];
    if (!src || src.startsWith("data:")) continue;

    const resolved = resolveUrl(src, pageUrl);
    if (!resolved) continue;
    if (isSkippedDomain(resolved)) continue;

    // Skip tiny SVGs and tracking pixels
    if (/\.svg$/i.test(resolved)) continue;
    if (/1x1|pixel|spacer|blank|transparent/i.test(resolved)) continue;

    const altMatch = tag.match(ALT_REGEX);
    const widthMatch = tag.match(WIDTH_REGEX);
    const heightMatch = tag.match(HEIGHT_REGEX);
    const w = widthMatch ? parseInt(widthMatch[1], 10) : null;
    const h = heightMatch ? parseInt(heightMatch[1], 10) : null;

    // Skip images smaller than 100x100
    if (w !== null && h !== null && (w < 100 || h < 100)) continue;
    // Skip single-dimension tiny images
    if ((w !== null && w < 50) || (h !== null && h < 50)) continue;

    const alt = altMatch ? altMatch[1] : "";

    images.push({
      url: resolved,
      altText: alt,
      width: w,
      height: h,
      category: categorize(resolved, alt),
      sourcePage: pageUrl,
    });
  }

  return images;
}

async function fetchPage(url: string): Promise<string | null> {
  try {
    const res = await fetch(url, {
      headers: { "User-Agent": "meSEO-ImageScanner/1.0" },
      signal: AbortSignal.timeout(10000),
    });
    if (!res.ok) return null;
    const ct = res.headers.get("content-type") || "";
    if (!ct.includes("text/html")) return null;
    return await res.text();
  } catch {
    return null;
  }
}

export async function scrapeWebsiteImages(
  domain: string,
  brandId: string,
): Promise<ScrapedImage[]> {
  // Check cache
  const cached = cache.get(domain);
  if (cached && Date.now() - cached.ts < CACHE_TTL) return cached.images;

  const baseUrl = domain.startsWith("http") ? domain : `https://${domain}`;

  // Get top pages from GSC to scrape
  const d30 = new Date(Date.now() - 30 * 86400000);
  const topPages = await prisma.gscPage.groupBy({
    by: ["pageUrl"],
    where: { brandId, date: { gte: d30 } },
    _sum: { clicks: true },
    orderBy: { _sum: { clicks: "desc" } },
    take: 5,
  }).catch(() => []);

  const urlsToScrape = [baseUrl];
  for (const p of topPages) {
    if (p.pageUrl && !urlsToScrape.includes(p.pageUrl)) {
      urlsToScrape.push(p.pageUrl);
    }
  }

  // Fetch pages in parallel (max 6)
  const results = await Promise.allSettled(
    urlsToScrape.slice(0, 6).map((url) => fetchPage(url)),
  );

  const allImages: ScrapedImage[] = [];
  const seenUrls = new Set<string>();

  for (let i = 0; i < results.length; i++) {
    const result = results[i];
    if (result.status !== "fulfilled" || !result.value) continue;
    const pageImages = extractImagesFromHtml(result.value, urlsToScrape[i]);
    for (const img of pageImages) {
      if (!seenUrls.has(img.url)) {
        seenUrls.add(img.url);
        allImages.push(img);
      }
    }
  }

  // Cache results
  cache.set(domain, { images: allImages, ts: Date.now() });

  return allImages;
}
