/**
 * Console/Network-Error-Monitor für Playwright-Tests.
 *
 * Überwacht Browser-Pages auf:
 * - `pageerror`      – Uncaught Exceptions
 * - `console.error`  – Alle console.error()-Aufrufe
 * - `requestfailed`  – Fehlgeschlagene Netzwerk-Requests (nicht absichtlich abgebrochene)
 *
 * Verwendung in Fixtures:
 * ```ts
 * const monitor = attachConsoleMonitor(page)
 * // … setup …
 * await use(page)
 * monitor.assertNoErrors()
 * ```
 *
 * Fehler werden NICHT ignoriert, sondern in der App gefixt.
 * IGNORED_PATTERNS nur für Infrastructure-Rauschen, das nicht in der App liegt.
 */

import type { Page } from "@playwright/test"

// ── Whitelist (nur Infrastructure-Rauschen, keine App-Fehler) ────────

const IGNORED_PATTERNS: RegExp[] = [
    /browser-sync/i,
    /cc\.webmakers\.de/i,
    /sentry/i,
    /Failed to load resource: net::ERR_/i,
    /Failed to load resource: the server responded with a status of/i,
    /TypeError: Failed to fetch/i,
]

// ── Types ────────────────────────────────────────────────────────────

interface ConsoleError {
    type: "pageerror" | "console.error" | "request-failed"
    message: string
}

export interface ConsoleMonitor {
    getErrors(): ConsoleError[]
    assertNoErrors(): void
}

// ── Implementation ───────────────────────────────────────────────────

function isIgnored(text: string): boolean {
    return IGNORED_PATTERNS.some((pattern) => pattern.test(text))
}

export function attachConsoleMonitor(page: Page): ConsoleMonitor {
    const errors: ConsoleError[] = []

    // Inject script to capture detailed unhandled rejection info
    page.addInitScript(() => {
        window.addEventListener("unhandledrejection", (event) => {
            const reason = event.reason
            if (reason && typeof reason === "object" && !(reason instanceof Error)) {
                try {
                    const detail = JSON.stringify(
                        reason,
                        (_key, val) => {
                            if (val instanceof Response) return `[Response ${val.status} ${val.url}]`
                            if (val instanceof Request) return `[Request ${val.method} ${val.url}]`
                            return val
                        },
                        2
                    )
                    console.error(`[unhandled-rejection-detail] ${detail}`)
                } catch {
                    console.error(`[unhandled-rejection-detail] ${String(reason)}`)
                }
            }
        })
    })

    page.on("pageerror", (error) => {
        const msg = error.stack || error.message || String(error)
        if (!isIgnored(msg)) {
            errors.push({ type: "pageerror", message: msg })
        }
    })

    page.on("console", (msg) => {
        if (msg.type() === "error") {
            const text = msg.text()
            if (!isIgnored(text)) {
                errors.push({ type: "console.error", message: text })
            }
        }
    })

    page.on("requestfailed", (request) => {
        const failure = request.failure()?.errorText || "unknown"
        if (failure === "net::ERR_ABORTED" || failure === "net::ERR_FAILED") return
        const url = request.url()
        if (isIgnored(url)) return
        errors.push({
            type: "request-failed",
            message: `${request.method()} ${url} – ${failure}`,
        })
    })

    return {
        getErrors: () => [...errors],
        assertNoErrors() {
            if (errors.length > 0) {
                const summary = errors.map((e) => `  [${e.type}] ${e.message}`).join("\n")
                throw new Error(
                    `Browser-Fehler während des Tests erkannt (${errors.length}):\n${summary}\n\n` +
                        `→ Fehler in der App fixen, NICHT in IGNORED_PATTERNS aufnehmen!`
                )
            }
        },
    }
}
