#!/usr/bin/env python3
# Covers frontend button/API interaction audit: auth, navigation, config modals,
# registry/cluster health buttons, chart launch modes, copy action, instances, and mobile overflow.

import os

from playwright.sync_api import expect, sync_playwright


BASE_URL = os.environ.get("FRONTEND_URL", "http://localhost:18080")
ADMIN_USER = os.environ.get("ADMIN_USER", "admin")
ADMIN_PASS = os.environ["ADMIN_PASS"]


def login(page):
    page.goto(BASE_URL, wait_until="networkidle")
    if page.locator("input[type='password']").count() == 0:
        return
    page.locator("input:not([type='password'])").first.fill(ADMIN_USER)
    page.locator("input[type='password']").first.fill(ADMIN_PASS)
    page.get_by_role("button", name="Login").last.click()
    page.wait_for_url("**/home", timeout=15000)
    page.wait_for_load_state("networkidle")


def click_nav(page, name, index=0):
    button = page.get_by_role("button", name=name).nth(index)
    try:
        button.click(timeout=5000)
    except Exception:
        button.evaluate("element => element.click()")
    page.wait_for_load_state("networkidle")
    page.wait_for_timeout(400)


def click_if_present(locator, timeout=2500):
    if locator.count() == 0:
        return False
    locator.first.click(timeout=timeout)
    return True


def collect_console_error(errors, msg):
    text = msg.text
    ignored = [
        "Failed to load resource: the server responded with a status of 404",
        "[LaunchModal] Failed to load values schema",
        "No chart repositories found in this registry",
    ]
    if msg.type == "error" and not any(item in text for item in ignored):
        errors.append(text)


def assert_no_overlay_overflow(page):
    overflow = page.evaluate(
        "document.documentElement.scrollWidth > document.documentElement.clientWidth + 2"
    )
    assert not overflow, "page has horizontal overflow"


with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    context = browser.new_context(
        viewport={"width": 1440, "height": 950},
        permissions=["clipboard-read", "clipboard-write"],
    )
    page = context.new_page()
    errors = []
    page.on("pageerror", lambda exc: errors.append(str(exc)))
    page.on("console", lambda msg: collect_console_error(errors, msg))
    page.on("dialog", lambda dialog: dialog.dismiss())

    login(page)

    for label, nav_index, assertion in [
        ("Home", 0, "Operations Workbench"),
        ("Clusters", 0, "Configuration - Clusters"),
        ("Registries", 0, "Configuration - Registries"),
        ("Cluster Monitoring", 0, "Cluster"),
        ("Launch Instance", 0, "Chart Browser"),
        ("Instances", 0, "Instance"),
    ]:
        click_nav(page, label, nav_index)
        expect(page.locator("body")).to_contain_text(assertion, timeout=15000)
        assert_no_overlay_overflow(page)

    click_nav(page, "Registries", 0)
    page.get_by_role("button", name="Refresh").first.click()
    page.wait_for_load_state("networkidle")
    page.get_by_role("button", name="Add Registry").click()
    expect(page.get_by_text("Add Registry Configuration")).to_be_visible(timeout=5000)
    page.get_by_role("button", name="Cancel").click()
    if page.locator("button[title='Edit']").count() > 0:
        page.locator("button[title='Edit']").first.click()
        expect(page.get_by_text("Edit Registry Configuration")).to_be_visible(timeout=5000)
        if page.get_by_role("button", name="Test Connection").count() > 0:
            page.get_by_role("button", name="Test Connection").click()
            page.wait_for_timeout(800)
        page.get_by_role("button", name="Cancel").click()
    if page.locator("button[title='Delete']").count() > 0:
        page.locator("button[title='Delete']").first.click()
        page.wait_for_timeout(300)

    click_nav(page, "Clusters", 0)
    page.get_by_role("button", name="Refresh").first.click()
    page.wait_for_load_state("networkidle")
    page.get_by_role("button", name="Add Cluster").click()
    expect(page.get_by_text("Add Cluster Configuration")).to_be_visible(timeout=5000)
    page.get_by_role("button", name="Cancel").click()
    if page.locator("button[title='Test Connection']").count() > 0:
        page.locator("button[title='Test Connection']").first.click()
        page.wait_for_timeout(800)
    if page.locator("button[title='Edit']").count() > 0:
        page.locator("button[title='Edit']").first.click()
        expect(page.get_by_text("Edit Cluster Configuration")).to_be_visible(timeout=5000)
        page.get_by_role("button", name="Cancel").click()
    if page.locator("button[title='Delete']").count() > 0:
        page.locator("button[title='Delete']").first.click()
        page.wait_for_timeout(300)

    click_nav(page, "Launch Instance")
    expect(page.get_by_text("Chart Browser")).to_be_visible(timeout=15000)
    page.get_by_role("button", name="Refresh").first.click()
    page.wait_for_load_state("networkidle")
    if page.get_by_role("button", name="All tags").count() > 0:
        page.get_by_role("button", name="All tags").click()
        page.wait_for_load_state("networkidle")
        page.get_by_role("button", name="Charts", exact=True).click()
        page.wait_for_load_state("networkidle")
    if page.get_by_role("button", name="Copy").count() > 0:
        page.get_by_role("button", name="Copy").first.click()
        page.wait_for_timeout(300)
    if page.get_by_role("button", name="Launch").count() > 0:
        page.get_by_role("button", name="Launch").first.click()
        if page.get_by_role("button", name="Cancel").count() > 0:
            expect(page.get_by_role("heading", name="Launch Instance")).to_be_visible(timeout=10000)
            expect(page.get_by_role("button", name="Quick")).to_be_visible()
            page.get_by_role("button", name="YAML").click()
            page.locator("textarea").last.fill("replicaCount: 1\n")
            if page.get_by_role("button", name="Guided").is_enabled():
                page.get_by_role("button", name="Guided").click()
            page.get_by_role("button", name="Cancel").click()

    click_nav(page, "Instances", 0)
    page.get_by_role("button", name="Refresh").first.click()
    page.wait_for_load_state("networkidle")
    if page.get_by_role("button", name="Entries").count() > 0:
        page.get_by_role("button", name="Entries").first.click()
        expect(page.locator("body")).to_contain_text("Entries", timeout=5000)
        click_if_present(page.get_by_role("button", name="Close"))
    if page.get_by_role("button", name="Modify").count() > 0:
        page.get_by_role("button", name="Modify").first.click()
        expect(page.locator("body")).to_contain_text("Modify Instance", timeout=5000)
        if page.get_by_role("button", name="YAML").count() > 0:
            page.get_by_role("button", name="YAML").click()
        page.get_by_role("button", name="Cancel").click()
    if page.get_by_role("button", name="Delete", exact=True).count() > 0:
        delete_button = page.get_by_role("button", name="Delete", exact=True).first
        box = delete_button.bounding_box()
        viewport = page.viewport_size or {"width": 1440, "height": 950}
        assert box and box["x"] >= 0 and box["x"] + box["width"] <= viewport["width"], "Delete instance button overflows horizontally"
        delete_button.click()
        page.wait_for_timeout(300)

    mobile = browser.new_page(viewport={"width": 390, "height": 844}, is_mobile=True)
    mobile.on("pageerror", lambda exc: errors.append(str(exc)))
    mobile.on("console", lambda msg: collect_console_error(errors, msg))
    login(mobile)
    click_nav(mobile, "Launch Instance")
    expect(mobile.get_by_text("Chart Browser")).to_be_visible(timeout=15000)
    assert_no_overlay_overflow(mobile)

    browser.close()

    if errors:
        raise AssertionError("\n".join(errors[:12]))
