const fs = require("node:fs");
const path = require("node:path");

const { expect, test } = require("@playwright/test");

const evidence = path.resolve(__dirname, "../../docs/evidence/stage-6");
test.beforeAll(() => fs.mkdirSync(evidence, { recursive: true }));

async function authenticate(page) {
  await page.goto("/");
  await page.getByLabel("账号名").fill("stage6admin");
  await page.getByLabel("密码").fill("Stage6-pass-123!");
  await page.getByRole("button", { name: "登录", exact: true }).click();
  await expect(page.locator(".sidebar, .field-error")).toBeVisible();
  if (!(await page.locator(".sidebar").isVisible())) {
    await page.getByRole("tab", { name: "注册" }).click();
    await page.getByRole("button", { name: "注册并登录" }).click();
    await expect(page.locator(".sidebar")).toBeVisible();
  }
}

function summary() {
  return {
    context: {
      requested_date: "2026-07-30", actual_date: "2026-07-29", previous_date: "2026-07-28",
      observed_at: "2026-07-29T15:00:00+08:00", state: "final", carried_forward: true,
      message: "沿用最近真实收盘快照",
    },
    values: { temperature: 42, limit_up: 68, limit_down: 4, broken: 24, seal_rate: 73.9, amount: 1628000000000 },
  };
}

const overview = { up_count: 2960, down_count: 1980, flat_count: 112, limit_up: 68, limit_down: 4, broken: 24, seal_rate: 73.9, amount: 1628000000000 };

function history() {
  return Array.from({ length: 60 }, (_, index) => ({
    trade_date: `2026-07-${String(index + 1).padStart(2, "0")}`,
    temperature: 26 + index % 35, phase: index % 3 === 0 ? "退潮" : "修复",
    direction: index % 2 ? "升温" : "降温", positive_rate: 45 + index % 20,
    seal_rate: 60 + index % 20, limit_up: 30 + index, broken: 9 + index % 15,
    limit_down: 2 + index % 8, max_height: 3 + index % 5, amount: 1300000000000 + index * 1000000000,
  }));
}

function poolItems() {
  return Array.from({ length: 18 }, (_, index) => ({
    identifier: `${String(index + 1).padStart(6, "0")}.SZ`, code: String(index + 1).padStart(6, "0"),
    name: `样本股票${index + 1}`, streak: index % 5 + 1, change: 9.8 + index / 100,
    price: 10 + index, sector: index % 2 ? "半导体" : "机器人", first_time: "09:35", last_time: "14:20",
    open_times: index % 3, turnover_rate: 8 + index, amount: 300000000 + index * 10000000,
    seal_amount: 50000000 + index * 1000000, reason: index % 2 ? "国产替代" : "产业链催化",
  }));
}

function yesterdayItems() {
  const outcomes = ["晋级", "红盘", "断板", "炸板", "跌停"];
  return Array.from({ length: 15 }, (_, index) => ({
    identifier: `${String(index + 101).padStart(6, "0")}.SZ`, code: String(index + 101).padStart(6, "0"),
    name: `昨日样本${index + 1}`, prior_streak: index % 7 + 1, current_change: 10 - index,
    outcome: outcomes[index % outcomes.length], current_streak: index % outcomes.length === 0 ? index % 7 + 2 : 0,
    sector: "电子", reason: "事件催化",
  }));
}

function performanceItems() {
  return Array.from({ length: 7 }, (_, index) => ({
    level: 7 - index, count: 3 + index, advanced: index % 3, red: 1, broken: 1,
    opened: index % 2, limit_down: index === 6 ? 1 : 0, advance_rate: 28.6,
    positive_rate: 57.1, average_change: 2.35,
  }));
}

async function mockMarket(page) {
  await page.route("**/api/market/summary", (route) => route.fulfill({ contentType: "application/json", body: JSON.stringify(summary()) }));
  await page.route("**/api/market/workspaces/*", (route) => {
    const key = new URL(route.request().url()).pathname.split("/").pop();
    const base = { trade_date: "2026-07-29", observed_at: "2026-07-29T15:00:00+08:00", carried_forward: false, message: "", overview };
    if (key === "emotion") return route.fulfill({ contentType: "application/json", body: JSON.stringify({ ...base, sentiment: { score: 42, phase: "退潮", direction: "降温", day_change: -8, confidence: 92, transition_reason: "赚钱效应与连板结构同步转弱", stats: { positive_rate: 53.2, yesterday_count: 47 }, components: [{ key: "breadth", label: "市场宽度", score: 58, weight: 20 }, { key: "limit_ecology", label: "涨停生态", score: 62, weight: 25 }, { key: "profit_effect", label: "赚钱效应", score: 34, weight: 30 }, { key: "ladder_structure", label: "连板结构", score: 38, weight: 15 }, { key: "liquidity", label: "成交活跃度", score: 52, weight: 10 }] }, history: history() }) });
    if (key === "yesterday") return route.fulfill({ contentType: "application/json", body: JSON.stringify({ ...base, items: yesterdayItems() }) });
    if (key === "performance") return route.fulfill({ contentType: "application/json", body: JSON.stringify({ ...base, items: performanceItems() }) });
    return route.fulfill({ contentType: "application/json", body: JSON.stringify({ ...base, items: poolItems() }) });
  });
}

test("emotion and pool workspaces remain usable across desktop and mobile", async ({ page }) => {
  const consoleErrors = [];
  page.on("console", (message) => { if (message.type() === "error" && !message.text().includes("401 (Unauthorized)")) consoleErrors.push(message.text()); });
  await mockMarket(page);
  await authenticate(page);

  await expect(page.getByRole("heading", { name: "情绪周期" })).toBeVisible();
  await expect(page.getByText("情绪指标继续走弱")).toBeVisible();
  await expect(page.locator(".phase-warning")).not.toContainText("筛选门槛");
  await page.getByRole("button", { name: "60日" }).click();
  await expect(page.locator(".emotion-history-table tbody tr")).toHaveCount(60);
  expect(await page.evaluate(() => document.documentElement.scrollHeight > window.innerHeight)).toBe(true);
  const finalHistoryRow = page.locator(".emotion-history-table tbody tr").last();
  await finalHistoryRow.scrollIntoViewIfNeeded();
  expect(await finalHistoryRow.evaluate((row) => row.getBoundingClientRect().bottom <= window.innerHeight - 30)).toBe(true);
  await page.screenshot({ path: path.join(evidence, "emotion-light-1920x1080.jpg"), type: "jpeg", quality: 82 });

  await page.getByRole("link", { name: /涨停池/ }).click();
  await page.getByRole("button", { name: "3板+" }).click();
  await page.getByLabel("搜索股池").fill("样本股票5");
  await expect(page.locator(".data-table tbody tr")).toHaveCount(1);
  const statusbar = await page.locator(".statusbar").evaluate((element) => {
    const style = getComputedStyle(element);
    const rect = element.getBoundingClientRect();
    return { position: style.position, bottom: Math.round(window.innerHeight - rect.bottom) };
  });
  expect(statusbar).toEqual({ position: "fixed", bottom: 0 });
  await expect(page.getByText("5板")).toBeVisible();
  await page.getByRole("button", { name: "夜间" }).click();
  await page.screenshot({ path: path.join(evidence, "pool-dark-1920x1080.jpg"), type: "jpeg", quality: 82 });
  await page.setViewportSize({ width: 3840, height: 2160 });
  expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBe(0);
  const density = await page.evaluate(() => ({
    contentWidth: document.querySelector(".page-frame").getBoundingClientRect().width,
    fontSize: getComputedStyle(document.body).fontSize,
    topbarHeight: document.querySelector(".topbar").getBoundingClientRect().height,
  }));
  expect(density.contentWidth).toBeLessThanOrEqual(2200);
  expect(density.fontSize).toBe("13px");
  expect(density.topbarHeight).toBe(46);
  await page.screenshot({ path: path.join(evidence, "pool-dark-3840x2160.jpg"), type: "jpeg", quality: 82 });

  await page.getByRole("link", { name: /涨停表现/ }).click();
  await expect(page.getByText("7板")).toBeVisible();
  await expect(page.getByRole("heading", { name: "今日结论" })).toBeVisible();
  const performanceGeometry = await page.evaluate(() => {
    const layout = document.querySelector(".performance-layout").getBoundingClientRect();
    const levels = document.querySelector(".performance-levels").getBoundingClientRect();
    const conclusion = document.querySelector(".performance-conclusion").getBoundingClientRect();
    return {
      cards: document.querySelectorAll(".performance-level-card").length,
      topGap: Math.abs(levels.top - conclusion.top),
      conclusionRightGap: Math.abs(layout.right - conclusion.right),
      overflow: document.documentElement.scrollWidth - window.innerWidth,
    };
  });
  expect(performanceGeometry).toEqual({ cards: 7, topGap: 0, conclusionRightGap: 0, overflow: 0 });
  await page.setViewportSize({ width: 390, height: 844 });
  expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBe(0);
  await page.screenshot({ path: path.join(evidence, "performance-dark-390x844.jpg"), type: "jpeg", quality: 82 });
  expect(consoleErrors).toEqual([]);
});
