# -*- coding: utf-8 -*-
"""E2E tests for SPA shell navigation/runtime contracts."""

import pytest
import re
from playwright.sync_api import Page, expect


def _sidebar_links(page: Page):
    """Support both legacy and current shell nav selectors."""
    return page.locator("a.drawer-link[href], a.sidebar-item[data-route]")


def _fetch_json_status(page: Page, url: str):
    """Run fetch in browser context and return status/payload metadata."""
    return page.evaluate(
        """
        async (targetUrl) => {
            const response = await fetch(targetUrl, { cache: 'no-store' });
            let payload = null;
            try {
                payload = await response.json();
            } catch (_) {
                payload = null;
            }
            return { ok: response.ok, status: response.status, payload };
        }
        """,
        url,
    )


@pytest.mark.e2e
class TestPortalPage:
    """E2E tests for portal shell routing and drawer navigation."""

    def test_portal_loads_successfully(self, page: Page, app_server: str):
        page.goto(app_server)
        expect(page.locator("h1")).to_contain_text("MES 報表入口")

    def test_portal_has_sidebar_routes(self, page: Page, app_server: str):
        page.goto(app_server)

        expect(_sidebar_links(page).first).to_be_visible()
        expect(page.locator(".drawer-link:has-text('WIP 即時概況')")).to_be_visible()
        expect(page.locator(".drawer-link:has-text('設備即時概況')")).to_be_visible()
        expect(page.locator(".drawer-link:has-text('設備歷史績效')")).to_be_visible()
        expect(page.locator(".drawer-link:has-text('設備維修查詢')")).to_be_visible()

    def test_portal_sidebar_navigation_uses_direct_routes(self, page: Page, app_server: str):
        page.goto(app_server)

        first_route = _sidebar_links(page).first
        expect(first_route).to_be_visible()
        target_href = first_route.get_attribute("href")
        assert target_href, "sidebar route href missing"

        first_route.click()
        expect(page).to_have_url(re.compile(f".*{re.escape(target_href)}$"))
        assert page.locator("iframe").count() == 0, "Shell content must not use iframe"

    def test_portal_health_popup_clickable(self, page: Page, app_server: str):
        page.goto(app_server)

        trigger = page.locator(".health-trigger")
        expect(trigger).to_be_visible()
        expect(page.locator("#shellHealthPopup")).to_have_count(0)

        trigger.click()
        expect(page.locator("#shellHealthPopup")).to_be_visible()

        page.keyboard.press("Escape")
        expect(page.locator("#shellHealthPopup")).to_have_count(0)


@pytest.mark.e2e
class TestFrontendApiRuntime:
    """E2E tests for runtime API availability in browser context."""

    def test_wip_overview_can_call_summary_api_via_fetch(self, page: Page, app_server: str):
        page.goto(f"{app_server}/wip-overview")
        result = _fetch_json_status(page, "/api/wip/overview/summary")
        assert result["ok"] is True
        assert result["status"] == 200
        assert isinstance(result.get("payload"), dict)

    def test_wip_detail_can_call_workcenter_api_via_fetch(self, page: Page, app_server: str):
        page.goto(f"{app_server}/wip-detail")
        result = _fetch_json_status(page, "/api/wip/meta/workcenters")
        assert result["ok"] is True
        assert result["status"] == 200
        assert isinstance(result.get("payload"), dict)

    def test_global_mesapi_bridge_is_optional(self, page: Page, app_server: str):
        page.goto(f"{app_server}/wip-overview")

        runtime = page.evaluate(
            """
            () => ({
                hasFetch: typeof window.fetch === 'function',
                hasMesApi: typeof window.MesApi !== 'undefined',
                hasMesApiGet: Boolean(window.MesApi && typeof window.MesApi.get === 'function'),
            })
            """
        )
        assert runtime["hasFetch"] is True
        if runtime["hasMesApi"]:
            assert runtime["hasMesApiGet"] is True


@pytest.mark.e2e
class TestRoutePagesSmoke:
    """Basic smoke checks for key route pages."""

    def test_wip_overview_loads(self, page: Page, app_server: str):
        response = page.goto(f"{app_server}/wip-overview")
        assert response is not None and response.ok
        expect(page.locator("body")).to_be_visible()

    def test_wip_detail_loads(self, page: Page, app_server: str):
        response = page.goto(f"{app_server}/wip-detail")
        assert response is not None and response.ok
        expect(page.locator("body")).to_be_visible()

    def test_resource_page_loads(self, page: Page, app_server: str):
        response = page.goto(f"{app_server}/resource")
        assert response is not None and response.ok
        expect(page.locator("body")).to_be_visible()

    def test_tables_page_loads(self, page: Page, app_server: str):
        response = page.goto(f"{app_server}/tables")
        assert response is not None
        assert response.status in {200, 403}
        expect(page.locator("body")).to_be_visible()
        if response.status == 200:
            header = page.locator("h1")
            expect(header).to_be_visible()
            text = header.inner_text()
            assert "MES 數據表查詢工具" in text or "頁面開發中" in text

    def test_excel_query_page_loads(self, page: Page, app_server: str):
        response = page.goto(f"{app_server}/excel-query")
        assert response is not None
        assert response.status in {200, 403}
        expect(page.locator("body")).to_be_visible()


@pytest.mark.e2e
class TestConsoleAndErrorSignals:
    """Console/pageerror checks for SPA runtime stability."""

    def test_wip_overview_has_no_uncaught_page_errors(self, page: Page, app_server: str):
        errors = []
        page.on("pageerror", lambda error: errors.append(str(error)))
        page.goto(f"{app_server}/wip-overview")
        page.wait_for_timeout(2000)
        assert errors == [], f"Unexpected page errors: {errors[:3]}"

    def test_wip_overview_triggers_expected_api_requests(self, page: Page, app_server: str):
        observed = set()

        def on_response(resp):
            if "/api/wip/overview/summary" in resp.url:
                observed.add("summary")
            if "/api/wip/overview/matrix" in resp.url:
                observed.add("matrix")

        page.on("response", on_response)
        page.goto(f"{app_server}/wip-overview", wait_until="domcontentloaded")

        page.wait_for_timeout(5000)
        assert "summary" in observed
        assert "matrix" in observed
