// Tests for shared/nav.js — the lateral project-stage strip.
//
// The strip's render decision depends on location.protocol and
// location.pathname. file:// won't render at all (online-only). To
// exercise online behavior we spin up a tiny in-process HTTP server
// for this spec so the page can be served from http://127.0.0.1:<port>
// at arbitrary paths.

import { test, expect } from '@playwright/test';
import * as http from 'http';
import * as fs from 'fs';
import * as path from 'path';

const HTML_PATH = path.resolve('classifier/dist/classifier.html');

let server;
let baseUrl;

test.beforeAll(async () => {
    const html = fs.readFileSync(HTML_PATH, 'utf8');
    server = http.createServer((req, res) => {
        // Serve the same classifier HTML at every path. The strip's
        // detection logic uses location.pathname; the bytes don't have
        // to vary.
        res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
        res.end(html);
    });
    await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
    const port = server.address().port;
    baseUrl = `http://127.0.0.1:${port}`;
});

test.afterAll(async () => {
    if (server) await new Promise(resolve => server.close(resolve));
});

test.describe('shared/nav.js stage strip', () => {

    test('does NOT render at the deployment root', async ({ page }) => {
        await page.goto(`${baseUrl}/index.html`, { waitUntil: 'load' });
        await page.waitForSelector('.app-header', { timeout: 5000 });
        await expect(page.locator('.zddc-stage-strip')).toHaveCount(0);
    });

    test('renders for <project>/archive.html with archive active', async ({ page }) => {
        await page.goto(`${baseUrl}/projA/archive.html`, { waitUntil: 'load' });
        const strip = page.locator('.zddc-stage-strip');
        await expect(strip).toHaveCount(1);
        await expect(strip.locator('.zddc-stage-strip__project')).toHaveText('projA');

        const stages = await strip.locator('.zddc-stage').allTextContents();
        expect(stages).toEqual(['Archive', 'Working', 'Staging', 'Reviewing']);

        const active = strip.locator('.zddc-stage--active');
        await expect(active).toHaveCount(1);
        await expect(active).toHaveText('Archive');
        await expect(active).toHaveAttribute('aria-current', 'page');
    });

    test('renders for <project>/working/foo/mdedit.html with working active', async ({ page }) => {
        await page.goto(`${baseUrl}/projA/working/casey/mdedit.html`, { waitUntil: 'load' });
        const active = page.locator('.zddc-stage-strip .zddc-stage--active');
        await expect(active).toHaveText('Working');
    });

    test('stage links point to the canonical <project>/<stage>/ URLs', async ({ page }) => {
        await page.goto(`${baseUrl}/projA/staging/`, { waitUntil: 'load' });
        await page.waitForSelector('.zddc-stage-strip');

        const links = await page.evaluate(() => {
            const xs = document.querySelectorAll('.zddc-stage-strip .zddc-stage');
            return Array.from(xs).map(a => ({ text: a.textContent, href: a.getAttribute('href') }));
        });
        expect(links).toEqual([
            { text: 'Archive',   href: '/projA/archive.html' },
            { text: 'Working',   href: '/projA/working/' },
            { text: 'Staging',   href: '/projA/staging/' },
            { text: 'Reviewing', href: '/projA/reviewing/' },
        ]);
    });

    test('mounts immediately above the app-header', async ({ page }) => {
        await page.goto(`${baseUrl}/projA/archive.html`, { waitUntil: 'load' });
        const prev = await page.evaluate(() => {
            const h = document.querySelector('.app-header');
            return h && h.previousElementSibling && h.previousElementSibling.className;
        });
        expect(prev).toContain('zddc-stage-strip');
    });

});
