import { test, expect, type Page } from "@playwright/test";
import { execFileSync } from "node:child_process";

import { login } from "./auth";
async function fits(page: Page) {
    expect(
        await page.evaluate(
            () => document.documentElement.scrollWidth <= innerWidth + 1,
        ),
    ).toBeTruthy();
}

for (const level of ["college", "junior_high"]) {
    test(`Phase 1 ${level} forms: class setup, debt clearance, enrollment, amendment, final grade and membership end`, async ({
        page,
    }, info) => {
        test.setTimeout(180000);
        const fixture = JSON.parse(
            execFileSync("php", ["tests/browser/phase1-fixture.php", level], {
                encoding: "utf8",
            }),
        );
        const tag: string = fixture.tag;
        const errors: string[] = [];
        page.on("pageerror", (error) => errors.push(error.message));
        await login(page, "admin");
        await page.goto("/setup");
        await page
            .getByRole("tab", { name: "Subject Classes", exact: true })
            .click();
        const form = page.locator("form").filter({
            has: page.getByRole("button", {
                name: "Create Subject Class",
                exact: true,
            }),
        });
        await form
            .getByLabel("Branch", { exact: true })
            .selectOption(String(fixture.branch));
        await form
            .getByLabel("Department", { exact: true })
            .selectOption(String(fixture.department));
        await form
            .getByLabel("Enrollment period", { exact: true })
            .selectOption(String(fixture.period));
        await form
            .getByLabel("Course / school level", { exact: true })
            .selectOption(String(fixture.program));
        await form
            .getByLabel("Subject", { exact: true })
            .selectOption(String(fixture.subject));
        await form
            .getByLabel("Teacher", { exact: true })
            .selectOption(String(fixture.teacher));
        await form
            .getByLabel("Final-grade scale", { exact: true })
            .selectOption(String(fixture.policy));
        await form
            .getByLabel("Class code", { exact: true })
            .fill(tag + "-MAIN");
        await form.getByLabel("Class capacity", { exact: true }).fill("1");
        await form.getByLabel("Starts", { exact: true }).fill("09:00");
        await form.getByLabel("Ends", { exact: true }).fill("10:00");
        await form
            .getByRole("button", { name: "Create Subject Class", exact: true })
            .click();
        await expect(
            page.getByText("School setup saved.", { exact: true }),
        ).toBeVisible();
        await page.getByRole("tab", { name: "Sections", exact: true }).click();
        const link = page.locator("form").filter({
            has: page.locator('input[name="operation"][value="class_link"]'),
        });
        await link
            .getByLabel("Section", { exact: true })
            .selectOption(String(fixture.section));
        const options = await link
            .getByLabel("Subject Class", { exact: true })
            .locator("option")
            .allTextContents();
        await link.getByLabel("Subject Class", { exact: true }).selectOption({
            label: options.find((label) => label.includes(tag + "-MAIN"))!,
        });
        await link
            .getByRole("button", { name: "Save usual class", exact: true })
            .click();
        await expect(
            page.getByText("School setup saved.", { exact: true }),
        ).toBeVisible();

        await login(page, "enrollment");
        await page.goto("/enrollment-batches/" + fixture.batch);
        await page
            .getByRole("button", { name: "Add Student", exact: true })
            .click();
        let dialog = page.getByRole("dialog");
        await dialog.getByLabel("Search Student", { exact: true }).fill(tag);
        await dialog
            .getByLabel("Student", { exact: true })
            .selectOption(String(fixture.student));
        await dialog
            .getByRole("button", { name: "Begin enrollment", exact: true })
            .click();
        await expect(page).toHaveURL(/\/enrollment-applications\/\d+$/);
        const applicationUrl = page.url();
        await page
            .getByRole("button", {
                name: "Complete Assessment · Continue",
                exact: true,
            })
            .click();
        await page
            .getByLabel("Course", { exact: true })
            .selectOption(String(fixture.program));
        await page
            .getByLabel("Year / Grade", { exact: true })
            .selectOption(String(fixture.year));
        await page
            .getByRole("button", { name: "Load Course subjects", exact: true })
            .click();
        await expect(page.getByLabel("Section", { exact: true })).toHaveValue(
            String(fixture.section),
        );
        await expect(
            page.getByText("Assigned Course plan:", { exact: false }),
        ).toContainText("Phase 1 browser");
        await page
            .getByRole("button", {
                name: "Save subjects · Continue to Accounting",
                exact: true,
            })
            .click();
        await page
            .getByRole("button", {
                name: "Skip Accounting · Review Pre-COR",
                exact: true,
            })
            .click();
        await page
            .getByRole("button", {
                name: "Save pending enrollment",
                exact: true,
            })
            .click();
        await expect(
            page.getByRole("link", { name: "View saved Pre-COR", exact: true }),
        ).toBeVisible();
        await fits(page);
        await page
            .getByRole("link", {
                name: "Student enrollment record",
                exact: true,
            })
            .click();
        await expect(page).toHaveURL(/\/enrollments\/\d+$/);
        const enrollmentUrl = page.url();
        await expect(
            page.getByRole("button", {
                name: "Finalize enrollment",
                exact: true,
            }),
        ).toHaveCount(0);

        await login(page, "finance-staff");
        await page.goto("/finance?student=" + fixture.student);
        await expect(
            page.getByRole("button", {
                name: "Approve past-debt arrangement",
                exact: true,
            }),
        ).toHaveCount(0);
        await page
            .getByRole("button", {
                name: "Record Cleared / On Hold",
                exact: true,
            })
            .click();
        dialog = page.getByRole("dialog");
        await expect(
            dialog
                .getByLabel("Clearance decision", { exact: true })
                .locator('option[value="cleared"]'),
        ).toBeDisabled();
        await dialog
            .getByLabel("Reason / verification notes", { exact: true })
            .fill("Opening debt is awaiting a reviewed arrangement.");
        await dialog
            .getByRole("button", {
                name: "Record clearance decision",
                exact: true,
            })
            .click();
        await expect(dialog).not.toBeVisible();
        await login(page, "finance");
        await page.goto("/finance?student=" + fixture.student);
        await page
            .getByRole("button", {
                name: "Approve past-debt arrangement",
                exact: true,
            })
            .click();
        dialog = page.getByRole("dialog");
        await dialog
            .getByLabel("Approval reason", { exact: true })
            .fill("Reviewed and approved the documented payment request.");
        await dialog
            .getByLabel("Approved payment terms", { exact: true })
            .fill("PHP 100 due on the school-approved payment date.");
        await dialog
            .getByRole("button", {
                name: "Approve payment arrangement",
                exact: true,
            })
            .click();
        await expect(dialog).not.toBeVisible();
        await login(page, "finance-staff");
        await page.goto("/finance?student=" + fixture.student);
        await page
            .getByRole("button", {
                name: "Record Cleared / On Hold",
                exact: true,
            })
            .click();
        dialog = page.getByRole("dialog");
        await dialog
            .getByLabel("Clearance decision", { exact: true })
            .selectOption("cleared");
        await dialog
            .getByLabel("Reason / verification notes", { exact: true })
            .fill("Current payment conditions and arrangement verified.");
        await dialog
            .getByRole("button", {
                name: "Record clearance decision",
                exact: true,
            })
            .click();
        await expect(dialog).not.toBeVisible();
        await fits(page);

        await login(page, "registrar");
        await page.goto(applicationUrl);
        await page
            .getByRole("button", {
                name: "Save and confirm enrollment",
                exact: true,
            })
            .click();
        await expect(
            page.getByText("Enrollment confirmed. Official COR issued.", {
                exact: true,
            }),
        ).toBeVisible();
        await page.goto(enrollmentUrl);
        await page
            .getByRole("button", {
                name: "Amend subjects or class selections",
                exact: true,
            })
            .click();
        await page
            .getByLabel("Class for " + tag, { exact: true })
            .selectOption(String(fixture.alternate));
        await page
            .getByLabel("Amendment reason", { exact: true })
            .fill("Student requires the Tuesday class instead.");
        await page
            .getByRole("button", {
                name: "Apply amendment and issue new COR",
                exact: true,
            })
            .click();
        await expect(
            page.getByRole("link", { name: "View COR version 2", exact: true }),
        ).toBeVisible();
        await page.evaluate(() => window.scrollTo(0, 0));
        await expect(page.locator("main#main")).toHaveAttribute(
            "aria-busy",
            "false",
        );
        await page.screenshot({
            path: `design/implementation/phase1-enrollment-${level}-${info.project.name}.png`,
            fullPage: true,
        });
        await page.goto(enrollmentUrl + "/cor?version=1");
        await expect(
            page.getByText(tag + "-MAIN", { exact: true }),
        ).toBeVisible();
        await page.goto(enrollmentUrl + "/cor?version=2");
        await expect(
            page.getByText(tag + "-ALT", { exact: true }),
        ).toBeVisible();

        await login(page, fixture.teacher_email);
        await page.goto("/classes/" + fixture.alternate);
        await page
            .getByRole("button", { name: "Enter final grade", exact: true })
            .click();
        dialog = page.getByRole("dialog");
        if (level === "college")
            await dialog
                .getByLabel("Final subject grade", { exact: true })
                .selectOption("1.5");
        else
            await dialog
                .getByLabel("Final subject grade", { exact: true })
                .fill("85");
        await dialog
            .getByRole("button", {
                name: "Save draft final grade",
                exact: true,
            })
            .click();
        await expect(dialog).not.toBeVisible();
        await page
            .getByRole("button", { name: "Finalize final grades", exact: true })
            .click();
        await page
            .getByRole("dialog")
            .getByRole("button", { name: "Confirm", exact: true })
            .click();
        await expect(
            page.getByText("Passed · Official", { exact: true }),
        ).toBeVisible();
        await page
            .getByRole("button", { name: "Correct grade", exact: true })
            .click();
        dialog = page.getByRole("dialog");
        if (level === "college")
            await dialog
                .getByLabel("Final subject grade", { exact: true })
                .selectOption("5");
        else
            await dialog
                .getByLabel("Final subject grade", { exact: true })
                .fill("70");
        await dialog
            .getByLabel("Correction reason", { exact: true })
            .fill("Teacher verified an encoding correction.");
        await dialog
            .getByRole("button", {
                name: "Record grade correction",
                exact: true,
            })
            .click();
        await expect(
            page.getByText("Failed · Official", { exact: true }),
        ).toBeVisible();
        await fits(page);
        await page.evaluate(() => window.scrollTo(0, 0));
        await expect(page.locator("main#main")).toHaveAttribute(
            "aria-busy",
            "false",
        );
        await page.screenshot({
            path: `design/implementation/phase1-final-grade-${level}-${info.project.name}.png`,
            fullPage: true,
        });

        await login(page, "registrar");
        await page.goto(enrollmentUrl);
        await page
            .getByRole("button", {
                name: "Amend subjects or class selections",
                exact: true,
            })
            .click();
        await expect(
            page.getByLabel("Class for " + tag, { exact: true }),
        ).toBeDisabled();
        await page.goto("/sections");
        const section = page.locator("section.panel").filter({
            has: page.getByRole("heading", {
                name: tag + " Section A",
                exact: true,
            }),
        });
        await section.getByText("End membership", { exact: true }).click();
        await section
            .getByLabel("Reason", { exact: true })
            .fill("Student left this Section; academic records retained.");
        await section
            .getByRole("button", {
                name: "End Section membership",
                exact: true,
            })
            .click();
        await expect(
            section.getByText("No current members.", { exact: true }),
        ).toBeVisible();
        await page.goto("/classes/" + fixture.alternate);
        await expect(page.getByText(tag, { exact: true })).toBeVisible();
        await expect(
            page.getByText("Failed · Official", { exact: true }),
        ).toBeVisible();
        await page.goto("/students/" + fixture.student);
        await expect(
            page.getByText("No current Section", { exact: true }),
        ).toBeVisible();
        await expect(
            page.getByText(
                "Student left this Section; academic records retained.",
                { exact: false },
            ),
        ).toBeVisible();
        await fits(page);
        expect(errors).toEqual([]);
    });
}

test("additional Phase 1 role pages fit desktop and mobile", async ({
    page,
}) => {
    test.setTimeout(140000);
    const errors: string[] = [];
    page.on("pageerror", (error) => errors.push(error.message));
    for (const [role, paths] of Object.entries({
        dean: ["/", "/capacity", "/sections", "/schedule"],
        "finance-staff": ["/", "/finance"],
        enrollment: ["/", "/students", "/enrollments"],
        teacher: ["/schedule", "/classes?view=final-grades"],
        admin: ["/setup", "/schedule", "/sections"],
        registrar: ["/sections", "/capacity"],
    })) {
        await login(page, role);
        for (const path of paths) {
            await page.goto(path);
            await expect(page.locator("main#main")).toBeVisible();
            await fits(page);
        }
    }
    expect(errors).toEqual([]);
});
