import { mkdir, writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';

import { expect, test, type Page, type Route } from '@playwright/test';
import { gamePath, gameProfile, gameTrpcRoute } from './gameTestPaths.js';

const response = (data: unknown) => ({ result: { data } });
const operationNames = (route: Route) =>
    decodeURIComponent(new URL(route.request().url()).pathname.split('/trpc/')[1] ?? '').split(',');

const installArchive = async (page: Page) => {
    await page.addInitScript((profile) => {
        localStorage.setItem('sammo-game-token', 'ga_archive');
        localStorage.setItem('sammo-game-profile', profile);
    }, gameProfile);
    await page.route(gameTrpcRoute, async (route) => {
        const results = operationNames(route).map((operation) => {
            if (operation === 'auth.status') return response({ ok: true });
            if (operation === 'lobby.info') return response({ myGeneral: null });
            if (operation === 'archive.myPastPlays') {
                return response({
                    seasons: [
                        {
                            serverId: 'che_2024_01',
                            date: '2024-01-31T00:00:00.000Z',
                            season: 51,
                            scenario: 2,
                            scenarioName: '천하쟁패',
                            dynastyId: 7,
                            generals: [
                                {
                                    generalNo: 17,
                                    name: '관우',
                                    lastYearMonth: 21403,
                                    nationId: 2,
                                    nationName: '촉',
                                    nationColor: '#800000',
                                    leadership: 91,
                                    strength: 98,
                                    intel: 77,
                                    experience: 23000,
                                    dedication: 1200,
                                    officerLevel: 12,
                                    personal: '대담',
                                    special: '상재',
                                    special2: '신산',
                                    historyCount: 2,
                                },
                            ],
                        },
                    ],
                });
            }
            if (operation === 'archive.myPastPlayDetail') {
                return response({
                    serverId: 'che_2024_01',
                    generalNo: 17,
                    name: '관우',
                    lastYearMonth: 21403,
                    history: ['<C>●</>214년 3월: 촉에 임관', '<Y>●</>214년 1월: 성도에서 거병'],
                });
            }
            return { error: { message: `unhandled ${operation}`, data: { code: 'BAD_REQUEST' } } };
        });
        await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(results) });
    });
};

test('past plays is available without a current general and preserves desktop interaction geometry', async ({
    page,
}) => {
    await installArchive(page);
    await page.setViewportSize({ width: 1200, height: 900 });
    await page.goto('past-plays');

    const root = page.locator('.past-plays-page');
    await expect(root).toBeVisible();
    await expect(page.getByRole('heading', { name: '내 지난 플레이 보기' })).toBeVisible();
    await expect(page.getByText('천하쟁패 · 51기')).toBeVisible();
    await expect(page.locator('.general-name')).toHaveText('관우');
    await expect(page.getByRole('link', { name: '이 기수 국가 정보' })).toHaveAttribute('href', gamePath('/dynasty/7'));
    const historyToggle = page.locator('.history-toggle');
    await expect(historyToggle).toHaveText('보기 (2)');
    await historyToggle.click();
    await expect(page.getByText('214년 3월: 촉에 임관')).toBeVisible();
    await expect(historyToggle).toHaveAttribute('aria-expanded', 'true');

    const geometry = await root.evaluate((element) => {
        const rect = element.getBoundingClientRect();
        const titleRect = element.querySelector('.title-row')!.getBoundingClientRect();
        const tableRect = element.querySelector('table')!.getBoundingClientRect();
        const style = getComputedStyle(element);
        return {
            x: rect.x,
            width: rect.width,
            minHeight: rect.height,
            title: { x: titleRect.x, y: titleRect.y, width: titleRect.width },
            tableWidth: tableRect.width,
            color: style.color,
            backgroundColor: style.backgroundColor,
        };
    });
    expect(geometry).toMatchObject({
        x: 100,
        width: 1000,
        title: { x: 100, y: 0, width: 1000 },
        tableWidth: 1000,
        color: 'rgb(238, 238, 238)',
        backgroundColor: 'rgb(21, 21, 21)',
    });

    const refresh = page.getByRole('button', { name: '새로고침' });
    await refresh.hover();
    expect(await refresh.evaluate((element) => getComputedStyle(element).color)).toBe('rgb(135, 206, 235)');
    await refresh.focus();
    expect(await refresh.evaluate((element) => document.activeElement === element)).toBe(true);

    const artifactRoot = process.env.PAST_PLAYS_ARTIFACT_DIR;
    if (artifactRoot) {
        const output = resolve(artifactRoot);
        await mkdir(output, { recursive: true });
        await writeFile(resolve(output, 'desktop-computed-dom.json'), `${JSON.stringify(geometry, null, 2)}\n`);
        await page.screenshot({ path: resolve(output, 'desktop.png'), fullPage: true });
    }
});

test('past plays keeps the legacy-width table scrollable on a mobile viewport', async ({ page }) => {
    await installArchive(page);
    await page.setViewportSize({ width: 390, height: 844 });
    await page.goto('past-plays');

    const scroll = page.locator('.table-scroll');
    const metrics = await scroll.evaluate((element) => ({
        clientWidth: element.clientWidth,
        scrollWidth: element.scrollWidth,
        overflowX: getComputedStyle(element).overflowX,
    }));
    // The shared legacy shell keeps its historical 500 px minimum canvas.
    expect(metrics).toEqual({ clientWidth: 500, scrollWidth: 940, overflowX: 'auto' });
    await expect(page.locator('.title-row')).toHaveCSS('flex-direction', 'column');
});
