import { expect, test, type Page } from '@playwright/test';

async function activeScenes(page: Page): Promise<string[]> {
  return page.evaluate(() => window.__HONEY_GAME__.scene.getScenes(true).map((scene) => scene.scene.key));
}

test('title, movement, maps, corruption controls, and ending flow', async ({ page }) => {
  const errors: string[] = [];
  page.on('console', (message) => { if (message.type() === 'error') errors.push(message.text()); });
  page.on('pageerror', (error) => errors.push(error.message));

  await page.goto('/');
  await expect(page.locator('.name-form')).toBeVisible();
  await expect(page.locator('#player-name')).toHaveAttribute('placeholder', '小满');
  await page.screenshot({ path: '.qa/title.png' });
  await page.locator('#player-name').fill('验收员');
  await page.getByRole('button', { name: '进入蜜糖村' }).click();
  await expect.poll(() => activeScenes(page)).toContain('HouseScene');
  await expect.poll(() => activeScenes(page)).toContain('UIScene');

  const startX = await page.evaluate(() => (window.__HONEY_GAME__.scene.getScene('HouseScene') as unknown as { player: { x: number } }).player.x);
  await page.keyboard.down('ArrowRight'); await page.waitForTimeout(250); await page.keyboard.up('ArrowRight');
  const movedX = await page.evaluate(() => (window.__HONEY_GAME__.scene.getScene('HouseScene') as unknown as { player: { x: number } }).player.x);
  expect(movedX).toBeGreaterThan(startX);
  for (const [key, animation] of [['w', 'walk-up'], ['s', 'walk-down'], ['a', 'walk-left'], ['d', 'walk-right']] as const) {
    await page.keyboard.down(key); await page.waitForTimeout(80);
    const activeAnimation = await page.evaluate(() => (window.__HONEY_GAME__.scene.getScene('HouseScene') as unknown as { player: { anims: { currentAnim?: { key: string } } } }).player.anims.currentAnim?.key);
    expect(activeAnimation).toBe(animation);
    await page.keyboard.up(key);
  }
  await page.keyboard.down('ArrowLeft'); await page.waitForTimeout(1600); await page.keyboard.up('ArrowLeft');
  const boundedX = await page.evaluate(() => (window.__HONEY_GAME__.scene.getScene('HouseScene') as unknown as { player: { x: number } }).player.x);
  expect(boundedX).toBeGreaterThanOrEqual(5);

  await page.keyboard.press('Backquote');
  await expect(page.locator('.debug-panel')).toBeVisible();
  await page.locator('[data-field="happiness"]').fill('100');
  await page.locator('[data-action="happiness"]').click();
  await page.locator('[data-field="awareness"]').fill('72');
  await page.locator('[data-action="awareness"]').click();
  await page.locator('[data-field="day"]').fill('7');
  await page.locator('[data-action="day"]').click();
  const state = await page.evaluate(() => {
    const d = window.__HONEY_GAME__.registry.get('director') as { snapshot: { happiness: number; awareness: number; day: number }; stage: string };
    return { ...d.snapshot, stage: d.stage };
  });
  expect(state).toMatchObject({ happiness: 100, awareness: 72, day: 7, stage: 'S4' });
  await page.screenshot({ path: '.qa/debug.png' });

  const maps = ['HouseScene', 'PlazaScene', 'BakeryScene', 'ShopScene', 'ClinicScene', 'LakeScene', 'FieldScene', 'WellScene', 'MistScene', 'WhiteScene'];
  for (const key of maps) {
    await page.locator('[data-field="scene"]').selectOption(key);
    await page.locator('[data-action="teleport"]').click();
    await expect.poll(() => activeScenes(page)).toContain(key);
  }

  await page.locator('[data-field="scene"]').selectOption('PlazaScene');
  await page.locator('[data-action="teleport"]').click();
  await expect.poll(() => activeScenes(page)).toContain('PlazaScene');
  await page.keyboard.press('Backquote');
  await page.screenshot({ path: '.qa/plaza-s4.png' });
  await page.keyboard.press('Backquote');
  await page.locator('[data-field="happiness"]').fill('40');
  await page.locator('[data-action="happiness"]').click();
  await page.locator('[data-field="day"]').fill('1');
  await page.locator('[data-action="day"]').click();
  await page.keyboard.press('Backquote');
  await page.waitForTimeout(2000);
  await page.screenshot({ path: '.qa/plaza-s1.png' });
  await page.evaluate(() => {
    const ui = window.__HONEY_GAME__.scene.getScene('UIScene') as unknown as { showDialogue: (options: object) => Promise<unknown> };
    void ui.showDialogue({ speaker: '阿福', text: '早上好呀！今天的幸福任务贴在板上啦。祝你开心！', portrait: 2 });
  });
  await page.waitForTimeout(100);
  await page.screenshot({ path: '.qa/dialogue.png' });
  await page.keyboard.press('e');
  await page.keyboard.press('Backquote');
  await page.locator('[data-action="clues"]').click();
  const clueCount = await page.evaluate(() => (window.__HONEY_GAME__.registry.get('director') as { snapshot: { clues: Set<string> } }).snapshot.clues.size);
  expect(clueCount).toBe(9);
  await page.locator('[data-ending="E3"]').click();
  await expect.poll(() => activeScenes(page)).toContain('EndingScene');
  await page.waitForTimeout(3200);
  await page.screenshot({ path: '.qa/e3.png' });
  expect(errors).toEqual([]);
});

test('integer scaling stays sharp at desktop and compact viewport', async ({ page }) => {
  await page.goto('/');
  await page.locator('#player-name').press('Enter');
  await expect.poll(() => activeScenes(page)).toContain('HouseScene');
  const desktop = await page.locator('canvas').boundingBox();
  expect(desktop?.width).toBe(960);
  expect(desktop?.height).toBe(540);
  await page.setViewportSize({ width: 640, height: 360 });
  await page.waitForTimeout(250);
  const compact = await page.locator('canvas').boundingBox();
  expect(compact?.width).toBe(640);
  expect(compact?.height).toBe(360);
});

test('all four forced endings render their specified evidence', async ({ page }) => {
  const startEnding = async (ending: string, name = '小满') => {
    await page.goto('/');
    await page.locator('#player-name').fill(name);
    await page.locator('#player-name').press('Enter');
    await expect.poll(() => activeScenes(page)).toContain('HouseScene');
    await page.evaluate((id) => (window.__HONEY_GAME__.registry.get('director') as { emit: (event: string, ending: string) => void }).emit('force-ending', id), ending);
    await expect.poll(() => activeScenes(page)).toContain('EndingScene');
  };
  const texts = () => page.evaluate(() => (window.__HONEY_GAME__.scene.getScene('EndingScene') as unknown as { children: { list: Array<{ type?: string; text?: string }> } }).children.list
    .filter((child) => child.type === 'Text')
    .map((text) => text.text ?? ''));

  await startEnding('E1');
  expect((await texts()).join('\n')).toContain('从此，每一天都很幸福。\n\n每一天。');
  await startEnding('E2'); await page.waitForTimeout(2200);
  expect((await texts()).join('\n')).toContain('疗程重新开始。');
  await startEnding('E3', '真实姓名'); await page.waitForTimeout(3200);
  const record = (await texts()).join('\n');
  expect(record).toContain('蜜糖谷情绪疗养中心');
  expect(record).toContain('姓名：真实姓名');
  expect(record).toContain('编号：PT-07');
  expect(record).toMatch(/疗程时长：\d{2}:\d{2}/);
  await page.waitForTimeout(2900);
  expect((await texts()).join('\n')).toContain('微笑消失了。');
  await startEnding('E4');
  expect((await texts()).join('\n')).toContain('系统检测到疗程无效。');
});
