import { expect, test } from "@playwright/test";

/**
 * Regression coverage for the four mobile-blog layout bugs:
 *
 * 1. Hero text too close to the header.
 * 2. Gap between title and intro too big (80px instead of ~24px).
 * 3. Intro runs to the viewport edge on the left.
 * 4. Post card runs to the viewport edge on the right.
 *
 * Tests run against the local Herd site where the rebuilt theme.css is
 * served. The live deployment (solowebdesigns.net) will pick up the
 * rebuilt CSS when the user deploys.
 */

const blogUrl = "http://community-works-collaborative.test/blog/";

test.describe("blog page mobile layout", () => {
    test.use({ viewport: { width: 402, height: 874 } });

    test("hero has top padding so it isn't glued to the header", async ({
        page,
    }) => {
        await page.goto(blogUrl, { waitUntil: "networkidle" });

        const data = await page.evaluate(() => {
            const header = document.querySelector(".site-header");
            const hero = document.querySelector(".page-hero");
            const heading = document.querySelector(".page-hero__heading");
            const cs = hero ? getComputedStyle(hero) : null;
            return {
                headerBottom: header ? Math.round(header.getBoundingClientRect().bottom) : null,
                heroTop: hero ? Math.round(hero.getBoundingClientRect().top) : null,
                heroPaddingTop: cs ? cs.paddingTop : null,
                headingTop: heading ? Math.round(heading.getBoundingClientRect().top) : null,
            };
        });

        // The hero must have some top padding (>= 8px) on mobile.
        const pt = parseFloat(data.heroPaddingTop) || 0;
        expect(
            pt,
            `hero paddingTop should be >= 8px on mobile, got ${pt}`,
        ).toBeGreaterThanOrEqual(8);

        // The heading shouldn't be touching the bottom of the header.
        const gap = data.headingTop - data.headerBottom;
        expect(
            gap,
            `heading should sit at least 8px below the header, got ${gap}px`,
        ).toBeGreaterThanOrEqual(8);
    });

    test("title-to-intro gap is ~24px (not 80px) on mobile", async ({
        page,
    }) => {
        await page.goto(blogUrl, { waitUntil: "networkidle" });

        const gap = await page.evaluate(() => {
            const heading = document.querySelector(".page-hero__heading");
            const intro = document.querySelector(".page-hero__intro");
            if (!heading || !intro) return null;
            const hRect = heading.getBoundingClientRect();
            const iRect = intro.getBoundingClientRect();
            return Math.round(iRect.top - hRect.bottom);
        });

        expect(gap, `title-to-intro gap should be ~24px, got ${gap}px`).toBeLessThanOrEqual(40);
    });

    test("hero intro is padded from the left edge", async ({ page }) => {
        await page.goto(blogUrl, { waitUntil: "networkidle" });

        const data = await page.evaluate(() => {
            const intro = document.querySelector(".page-hero__intro");
            const heading = document.querySelector(".page-hero__heading");
            if (!intro || !heading) return null;
            return {
                introX: Math.round(intro.getBoundingClientRect().x),
                headingX: Math.round(heading.getBoundingClientRect().x),
                winW: window.innerWidth,
            };
        });

        // The intro should have at least 16px of left padding from the viewport edge.
        expect(
            data.introX,
            `intro x=${data.introX} should be >= 16`,
        ).toBeGreaterThanOrEqual(16);
        expect(
            data.headingX,
            `heading x=${data.headingX} should be >= 16`,
        ).toBeGreaterThanOrEqual(16);
    });

    test("intro has bottom margin so it doesn't sit on the first card", async ({
        page,
    }) => {
        await page.goto(blogUrl, { waitUntil: "networkidle" });

        const data = await page.evaluate(() => {
            const intro = document.querySelector(".page-hero__intro");
            const firstCard = document.querySelector(".post-list__post");
            if (!intro || !firstCard) return null;
            const cs = intro ? getComputedStyle(intro) : null;
            const iRect = intro.getBoundingClientRect();
            const cRect = firstCard.getBoundingClientRect();
            return {
                introMarginBottom: cs ? cs.marginBottom : null,
                introBottom: Math.round(iRect.bottom),
                cardTop: Math.round(cRect.top),
                gap: Math.round(cRect.top - iRect.bottom),
            };
        });

        // The intro must have a non-zero bottom margin.
        const mb = parseFloat(data.introMarginBottom) || 0;
        expect(
            mb,
            `intro marginBottom should be >= 16px, got ${mb}`,
        ).toBeGreaterThanOrEqual(16);

        // The intro should sit at least 16px above the first card.
        expect(
            data.gap,
            `intro-to-card gap should be >= 16px, got ${data.gap}px`,
        ).toBeGreaterThanOrEqual(16);
    });

    test("post card fits within the viewport on mobile", async ({ page }) => {
        await page.goto(blogUrl, { waitUntil: "networkidle" });

        const data = await page.evaluate(() => {
            const card = document.querySelector(".post-list__post");
            if (!card) return null;
            const r = card.getBoundingClientRect();
            return {
                x: Math.round(r.x),
                w: Math.round(r.width),
                right: Math.round(r.right),
                winW: window.innerWidth,
            };
        });

        // The card must not overflow the viewport on either side.
        expect(
            data.x,
            `card x=${data.x} should be >= 0`,
        ).toBeGreaterThanOrEqual(0);
        expect(
            data.right,
            `card right=${data.right} should be <= ${data.winW}`,
        ).toBeLessThanOrEqual(data.winW);
    });

    test("no horizontal overflow on the blog page at 402", async ({
        page,
    }) => {
        await page.goto(blogUrl, { waitUntil: "networkidle" });

        const data = await page.evaluate(() => ({
            docW: document.documentElement.scrollWidth,
            winW: window.innerWidth,
        }));

        expect(
            data.docW,
            `docW=${data.docW} exceeds winW=${data.winW}`,
        ).toBeLessThanOrEqual(data.winW + 1);
    });
});

test.describe("blog page mobile layout (xs 360)", () => {
    test.use({ viewport: { width: 360, height: 800 } });

    test("post card fits within 360px viewport", async ({ page }) => {
        await page.goto(blogUrl, { waitUntil: "networkidle" });

        const data = await page.evaluate(() => {
            const card = document.querySelector(".post-list__post");
            if (!card) return null;
            const r = card.getBoundingClientRect();
            return { x: Math.round(r.x), w: Math.round(r.width), right: Math.round(r.right), winW: window.innerWidth };
        });

        expect(data.x).toBeGreaterThanOrEqual(0);
        expect(data.right).toBeLessThanOrEqual(data.winW);
    });
});
