/// <reference types="cypress" />

/**
 * Mobile UX Regression Tests
 *
 * Verifies that the mobile UX cleanup for logged-out pages, family
 * registration, dashboards, profile views, and editors holds up on a
 * 375×812 (iPhone X) viewport — no horizontal scroll, form fields stack,
 * buttons wrap, touch targets are large enough.
 */

const MOBILE_VIEWPORT = [375, 812];

/** Assert the document has no horizontal overflow at the current viewport. */
function assertNoHorizontalOverflow() {
    cy.document().then((doc) => {
        const scrollWidth = doc.documentElement.scrollWidth;
        const clientWidth = doc.documentElement.clientWidth;
        // Allow 2px tolerance for rounding / scrollbar
        expect(scrollWidth, "document scrollWidth").to.be.lessThan(clientWidth + 3);
    });
}

describe("Mobile UX — Logged-Out Pages", () => {
    beforeEach(() => {
        cy.viewport(...MOBILE_VIEWPORT);
    });

    it("login page fits mobile viewport without horizontal scroll", () => {
        cy.visit("/session/begin");
        cy.get("body").should("have.class", "page-auth");
        cy.get(".login-container").should("be.visible");
        cy.get("input[name='User']").should("be.visible");
        cy.get("input[name='Password']").should("be.visible");
        cy.get(".btn-sign-in").should("be.visible");
        assertNoHorizontalOverflow();
    });

    it("login inputs use 16px font to prevent iOS auto-zoom", () => {
        cy.visit("/session/begin");
        cy.get("input[name='User']").then(($el) => {
            const fontSize = parseFloat($el.css("font-size"));
            expect(fontSize, "input font-size").to.be.gte(16);
        });
    });

    it("auth footer social icons meet 44px minimum touch target", () => {
        cy.visit("/session/begin");
        cy.get(".auth-footer-social a").first().then(($el) => {
            const width = parseFloat($el.css("width"));
            const height = parseFloat($el.css("height"));
            expect(width, "social link width").to.be.gte(44);
            expect(height, "social link height").to.be.gte(44);
        });
    });

    it("password reset page fits mobile viewport", () => {
        cy.visit("/session/forgot-password/reset-request");
        cy.get(".forgot-password-card").should("be.visible");
        cy.get("input[name='username']").should("be.visible");
        cy.get(".btn-reset").should("be.visible");
        assertNoHorizontalOverflow();
    });

    it("password reset error page fits mobile viewport", () => {
        cy.visit("/session/forgot-password/set/invalid-token-mobile-test");
        cy.get(".alert.alert-danger").should("be.visible");
        cy.get(".alert-buttons a, .alert-buttons button")
            .should("have.length.at.least", 1);
        assertNoHorizontalOverflow();
    });
});

describe("Mobile UX — Family Registration", () => {
    beforeEach(() => {
        cy.viewport(...MOBILE_VIEWPORT);
    });

    it("family register page fits mobile viewport and fields stack", () => {
        cy.visit("/external/register/");
        cy.get("#registration-stepper").should("be.visible");
        cy.get("#familyName").should("be.visible");
        cy.get("#familyAddress1").should("be.visible");
        assertNoHorizontalOverflow();
    });

    it("family register form inputs use 16px font (iOS zoom prevention)", () => {
        cy.visit("/external/register/");
        cy.get("#familyName").then(($el) => {
            const fontSize = parseFloat($el.css("font-size"));
            expect(fontSize, "input font-size").to.be.gte(16);
        });
    });

    it("family register step nav buttons take full width on mobile", () => {
        cy.visit("/external/register/");
        cy.get("#family-info-next").then(($btn) => {
            const btnWidth = $btn.outerWidth();
            const parentWidth = $btn.parent().innerWidth();
            // Stacked buttons should be at least ~90% of parent width
            expect(btnWidth / parentWidth, "button width ratio").to.be.gte(0.9);
        });
    });
});

describe("Mobile UX — Authenticated Pages", () => {
    beforeEach(() => {
        cy.viewport(...MOBILE_VIEWPORT);
        cy.setupStandardSession();
    });

    it("root dashboard fits mobile viewport without horizontal scroll", () => {
        cy.visit("/v2/dashboard");
        cy.get(".page-body").should("be.visible");
        // Wait for DataTables to finish initializing (async AJAX + render)
        // before checking overflow, otherwise columns may still be resizing.
        cy.get("#latestFamiliesDashboardItem_wrapper", { timeout: 15000 })
            .should("be.visible");
        assertNoHorizontalOverflow();
    });

    it("root dashboard birthday/anniversary tables are wrapped in table-responsive", () => {
        // NOTE: latestFamilies/Person tables intentionally have NO .table-responsive
        // wrapper because they have row action dropdowns — .table-responsive sets
        // overflow:auto which clips dropdowns. See responsive-design-guidelines.md.
        // Birthday/Anniversary tables have no row actions, so they CAN be wrapped.
        cy.visit("/v2/dashboard");
        cy.get("#PersonBirthdayDashboardItem")
            .parents(".table-responsive")
            .should("exist");
        cy.get("#FamiliesWithAnniversariesDashboardItem")
            .parents(".table-responsive")
            .should("exist");
    });

    it("groups dashboard renders without clipping action dropdowns on mobile", () => {
        // #groupsTable has per-row action dropdowns so it is intentionally NOT
        // wrapped in .table-responsive — that would set overflow:auto on the
        // wrapper and clip absolutely-positioned dropdown menus on the last
        // rows. The card-body uses `style="overflow: visible;"` instead, and
        // the documented trade-off is to accept some horizontal overflow on
        // phones rather than break the action menus.
        // See `.agents/skills/churchcrm/responsive-design-guidelines.md` →
        // "Tables must be wrapped — but NOT with .table-responsive if the
        // rows have action dropdowns" for the full rationale.
        //
        // This test asserts the policy invariants (table is rendered, the
        // wrapper is NOT .table-responsive, dropdowns are reachable in the
        // DOM) instead of asserting no horizontal overflow.
        cy.visit("/groups/dashboard");
        cy.get("#groupsTable_wrapper", { timeout: 15000 }).should("be.visible");

        // Policy invariant 1: table is NOT wrapped in .table-responsive
        cy.get("#groupsTable")
            .parents(".table-responsive")
            .should("not.exist");

        // Policy invariant 2: card-body that hosts the table allows
        // overflow:visible so dropdowns can escape the card boundary
        cy.get("#groupsTable")
            .closest(".card-body")
            .should("have.attr", "style")
            .and("match", /overflow:\s*visible/);
    });

    it("family view stacks columns on mobile", () => {
        cy.visit("/people/family/1");
        // Both main and sidebar columns should be visible (stacked on mobile)
        cy.get(".col-12.col-lg-8").should("be.visible");
        cy.get(".col-12.col-lg-4").should("be.visible");
        assertNoHorizontalOverflow();
    });

    it("PersonEditor form fields stack full-width on mobile", () => {
        cy.visit("/PersonEditor.php");
        cy.get("#FirstName").should("be.visible").then(($el) => {
            // First name field should take most of the viewport width (col-12 on mobile)
            const fieldWidth = $el.closest(".mb-3").outerWidth();
            const containerWidth = $el.closest(".row").innerWidth();
            expect(fieldWidth / containerWidth, "first name column ratio")
                .to.be.gte(0.9);
        });
        assertNoHorizontalOverflow();
    });

    it("FamilyEditor form fields stack full-width on mobile", () => {
        cy.visit("/FamilyEditor.php");
        cy.get("#FamilyName").should("be.visible").then(($el) => {
            const fieldWidth = $el.closest(".mb-3").outerWidth();
            const containerWidth = $el.closest(".row").innerWidth();
            expect(fieldWidth / containerWidth, "family name column ratio")
                .to.be.gte(0.9);
        });
        assertNoHorizontalOverflow();
    });
});
