import { chromium, Browser, Page, BrowserContext } from "playwright";
import { BaseScraper } from "./baseScraper";
import { Property } from "../types/property";

const VIEWPORTS = [
    { width: 1280, height: 800 },
    { width: 1366, height: 768 },
    { width: 1920, height: 1080 },
    { width: 1440, height: 900 },
];

const LOCALES = ["es-ES", "es", "ca-ES"];

// User agents actualizados (Chrome 129-131, Firefox 133)
const PW_USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0",
];

function randomItem<T>(arr: T[]): T {
    return arr[Math.floor(Math.random() * arr.length)];
}

function sleep(ms: number): Promise<void> {
    return new Promise(r => setTimeout(r, ms));
}

export abstract class PlaywrightBaseScraper extends BaseScraper {
    protected waitForSelector?: string;
    protected pageTimeoutMs = 30000;

    constructor(baseUrl: string, sourceName: string) {
        super(baseUrl, sourceName);
    }

    abstract scrape(): Promise<Property[]>;

    /**
     * Lanza Chromium headless, navega a la URL y retorna el HTML renderizado.
     * Incluye cabeceras stealth, viewport aleatorio y manejo de modales de cookies.
     */
    protected async fetchHtmlPlaywright(url: string, waitFor?: string): Promise<string> {
        let browser: Browser | null = null;
        try {
            browser = await chromium.launch({
                headless: true,
                args: [
                    "--disable-blink-features=AutomationControlled",
                    "--no-sandbox",
                    "--disable-setuid-sandbox",
                ],
            });

            const viewport = randomItem(VIEWPORTS);
            const locale = randomItem(LOCALES);
            const userAgent = randomItem(PW_USER_AGENTS);

            const context: BrowserContext = await browser.newContext({
                viewport,
                locale,
                timezoneId: "Europe/Madrid",
                userAgent,
                javaScriptEnabled: true,
                ignoreHTTPSErrors: true,
                extraHTTPHeaders: {
                    "Accept-Language": "es-ES,es;q=0.9",
                    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
                },
            });

            // Override detection properties with stealth script
            await context.addInitScript(() => {
                Object.defineProperty(navigator, "webdriver", { get: () => undefined });
                // No fake plugins – native PluginArray avoids bot-detection fingerprint failures
                Object.defineProperty(navigator, "languages", { get: () => ["es-ES", "es"] });
                (window as any).chrome = { runtime: {} };
            });

            const page: Page = await context.newPage();

            // Small random delay before navigation
            await sleep(300 + Math.random() * 700);

            await page.goto(url, {
                waitUntil: "load",
                timeout: this.pageTimeoutMs,
            });

            // Small pause to let deferred JS start running
            await sleep(1000 + Math.random() * 500);

            // Accept cookie banners
            await this.dismissCookieBanner(page);

            // Wait for content selector if specified
            const selector = waitFor || this.waitForSelector;
            if (selector) {
                try {
                    await page.waitForSelector(selector, { timeout: this.pageTimeoutMs });
                } catch {
                    console.warn(`[${this.sourceName}] Selector "${selector}" no encontrado en ${url}`);
                }
            } else {
                await sleep(1500 + Math.random() * 1000);
            }

            const html = await page.content();
            return html;
        } catch (error: any) {
            console.error(`[${this.sourceName}] Error Playwright en ${url}: ${error.message}`);
            return "";
        } finally {
            if (browser) await browser.close();
        }
    }

    /** Intenta hacer clic en botones de aceptar cookies comunes */
    protected async dismissCookieBanner(page: Page): Promise<void> {
        const cookieSelectors = [
            "#onetrust-accept-btn-handler",
            "[id*='accept'][id*='cookie']",
            "[class*='cookie-accept']",
            "[class*='cookieConsent'] button",
            "button[data-testid='accept-cookies']",
            "button[title*='Aceptar']",
            "button[aria-label*='Aceptar']",
            ".didomi-continue-btn",
            "#didomi-notice-agree-button",
            "button:text('Aceptar')",
            "button:text('Aceptar todo')",
            "button:text('Aceptar todas')",
            "button:text('Accept')",
            "button:text('Accept all')",
        ];

        for (const sel of cookieSelectors) {
            try {
                const btn = page.locator(sel).first();
                const visible = await btn.isVisible({ timeout: 1500 }).catch(() => false);
                if (visible) {
                    await btn.click({ timeout: 2000 });
                    await sleep(500);
                    break;
                }
            } catch {
                // ignore
            }
        }
    }
}
