import { test, expect, type Page } from './fixtures';

// The global nav progress bar (rendered once in the root layout) is the only
// feedback most data routes have while a client-side navigation is pending:
// they run `load` with `ssr = false`, so SvelteKit holds the previous page on
// screen with no indication anything is happening. This drives a real
// home -> detail navigation, holds the detail's `getManga` open, and asserts
// the bar activates during the pending load and clears once it settles.

const mangaId = 'm1111111-1111-1111-1111-111111111111';

const listItem = {
    id: mangaId,
    title: 'Berserk',
    status: 'ongoing',
    alt_titles: [],
    description: null,
    cover_image_path: null,
    created_at: '2026-01-01T00:00:00Z',
    updated_at: '2026-01-01T00:00:00Z',
    authors: [],
    genres: []
};

const mangaDetail = {
    id: mangaId,
    title: 'Berserk',
    status: 'ongoing',
    alt_titles: [],
    description: null,
    cover_image_path: null,
    created_at: '2026-01-01T00:00:00Z',
    updated_at: '2026-01-01T00:00:00Z',
    authors: [],
    genres: [],
    tags: [],
    content_warnings: [],
    chapter_storage_bytes: 0
};

async function mockCommon(page: Page) {
    await page.route('**/api/v1/auth/config', (r) =>
        r.fulfill({
            status: 200,
            contentType: 'application/json',
            body: JSON.stringify({ self_register_enabled: true, private_mode: false })
        })
    );
    await page.route('**/api/v1/auth/me', (r) =>
        r.fulfill({
            status: 401,
            contentType: 'application/json',
            body: JSON.stringify({ error: { code: 'unauthenticated', message: 'no' } })
        })
    );
    await page.route('**/api/v1/auth/me/preferences', (r) =>
        r.fulfill({
            status: 401,
            contentType: 'application/json',
            body: JSON.stringify({ error: { code: 'unauthenticated', message: 'no' } })
        })
    );
    await page.route('**/api/v1/genres*', (r) =>
        r.fulfill({ status: 200, contentType: 'application/json', body: '[]' })
    );
    // Catalog list (Pattern B). Registered before the detail routes so the
    // more-specific handlers below win for the /mangas/:id URLs.
    await page.route('**/api/v1/mangas*', (r) =>
        r.fulfill({
            status: 200,
            contentType: 'application/json',
            body: JSON.stringify({ items: [listItem], page: { limit: 50, offset: 0, total: 1 } })
        })
    );
    // Detail load's non-manga calls.
    await page.route('**/api/v1/me/bookmarks*', (r) =>
        r.fulfill({
            status: 200,
            contentType: 'application/json',
            body: JSON.stringify({ items: [], page: { limit: 50, offset: 0, total: 0 } })
        })
    );
    await page.route(`**/api/v1/mangas/${mangaId}/chapters*`, (r) =>
        r.fulfill({
            status: 200,
            contentType: 'application/json',
            body: JSON.stringify({ items: [], page: { limit: 50, offset: 0, total: 0 } })
        })
    );
    await page.route(`**/api/v1/mangas/${mangaId}/similar`, (r) =>
        r.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ items: [] }) })
    );
    await page.route(`**/api/v1/me/read-progress/${mangaId}`, (r) =>
        r.fulfill({
            status: 404,
            contentType: 'application/json',
            body: JSON.stringify({ error: { code: 'not_found', message: 'no' } })
        })
    );
    await page.route(`**/api/v1/me/reactions/${mangaId}`, (r) =>
        r.fulfill({
            status: 404,
            contentType: 'application/json',
            body: JSON.stringify({ error: { code: 'not_found', message: 'no' } })
        })
    );
}

test('shows the nav progress bar during a pending navigation and clears it after', async ({
    page
}) => {
    await mockCommon(page);

    // Hold the detail's getManga open so the navigation stays pending long
    // enough to observe the bar. Registered last => wins for the exact
    // /mangas/:id URL over the catalog glob.
    let releaseDetail: () => void = () => {};
    const gate = new Promise<void>((resolve) => {
        releaseDetail = resolve;
    });
    await page.route(`**/api/v1/mangas/${mangaId}`, async (route) => {
        await gate;
        await route.fulfill({
            status: 200,
            contentType: 'application/json',
            body: JSON.stringify(mangaDetail)
        });
    });

    await page.goto('/');
    await expect(page.getByTestId('manga-list')).toBeVisible();

    const bar = page.getByTestId('nav-progress');
    // Idle on a settled page.
    await expect(bar).toHaveAttribute('data-phase', 'idle');

    // Client-side navigate into the (gated) detail page.
    await page.locator(`a[href="/manga/${mangaId}"]`).first().click();

    // Bar enters the loading phase while the detail load is in flight.
    await expect(bar).toHaveAttribute('data-phase', 'loading');

    // Let the load resolve; the detail renders and the bar settles back to
    // idle (via a brief done phase).
    releaseDetail();
    await expect(page.getByTestId('manga-title')).toHaveText('Berserk');
    await expect(bar).toHaveAttribute('data-phase', 'idle');
});
