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

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

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

async function contrastRatio(locator) {
  return locator.evaluate((element) => {
    const rgba = (value) => (value.match(/[\d.]+/g) ?? []).map(Number);
    const luminance = (value) => {
      const [r, g, b] = rgba(value).slice(0, 3).map((channel) => {
        const normalized = channel / 255;
        return normalized <= 0.03928 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4;
      });
      return 0.2126 * r + 0.7152 * g + 0.0722 * b;
    };
    let background = element;
    while (background && rgba(getComputedStyle(background).backgroundColor)[3] === 0) background = background.parentElement;
    const foregroundLuminance = luminance(getComputedStyle(element).color);
    const backgroundLuminance = luminance(getComputedStyle(background ?? document.documentElement).backgroundColor);
    return (Math.max(foregroundLuminance, backgroundLuminance) + 0.05) / (Math.min(foregroundLuminance, backgroundLuminance) + 0.05);
  });
}

async function authenticate(page, username, password) {
  await page.goto("/");
  await page.getByLabel("账号名").fill(username);
  await page.getByLabel("密码").fill(password);
  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();
  }
}

const lines = Array.from({ length: 6 }, (_, index) => ({
  position: index + 1,
  position_name: ["初爻", "二爻", "三爻", "四爻", "五爻", "上爻"][index],
  talent: ["地", "地", "人", "人", "天", "天"][index],
  layer: index % 2 ? "外" : "内",
  role: ["个股内核", "个股外显", "行业内核", "行业外显", "市场内核", "指数外显"][index],
  score: 0.42,
  value: index % 2 ? 8 : 7,
  moving: false,
}));

const hexagram = {
  name: "泰",
  text: "天地交而万物通。",
  inner_trigram: "乾",
  outer_trigram: "坤",
  lines,
  transformed: { name: "泰", inner_trigram: "乾", outer_trigram: "坤" },
};

const fortune = {
  date: "2026-07-30",
  lunar_date: "农历六月十七",
  pillars: { year: "丙午", month: "乙未", day: "乙巳" },
  solar_term: { current: "大暑", next: "立秋" },
  phrase: "湿热交蒸·燥中夹滞",
  movement: { element: "水", tendency: "太过" },
  six_qi: { sitian: "少阴君火", zaiquan: "阳明燥金", step: 4, step_name: "四之气", host: "太阴湿土", guest: "少阳相火" },
  layers: [
    { label: "年纲", dominant: "火", summary: "水运为纲，司天少阴君火" },
    { label: "客主加临", dominant: "土", summary: "客少阳相火加临主太阴湿土" },
    { label: "日辰触发", dominant: "木", summary: "乙巳日，只作轻量触发" },
  ],
  personal: { day_master_element: "木", tone: "当日主气与个人生扶倾向交错", notice: "个人信息只用于本地派生计算。" },
  sector_catalog: ["木", "火", "土", "金", "水"].map((element) => ({ element, industries: ["行业一", "行业二"] })),
  notice: "五行气场是传统历法与市场行为的象征性观察，不代表可验证的因果关系。",
};

const trendResult = {
  trade_date: "2026-07-30",
  stock: { identifier: "002141.SZ", code: "002141", name: "贤丰控股" },
  sector: { name: "元件" },
  hexagram,
  momentum_score: 42,
  momentum_label: "势起未极",
  checks: lines.map((line) => ({ position: line.position, position_name: line.position_name, role: line.role, passed: true, source: "automatic", message: "自动数据通过" })),
};

function reading(id, mode, result, interpretation = "") {
  return { id, mode, date: "2026-07-30", subject_key: "", result, interpretation, status: interpretation ? "complete" : "pending", created_at: "2026-07-30T10:00:00+08:00" };
}

async function mockHeaven(page) {
  const historical = reading(90, "trend", trendResult, "历史解势内容");
  await page.route("**/api/heaven/setup?*", (route) => route.fulfill({
    contentType: "application/json",
    body: JSON.stringify({ date: "2026-07-30", fortune, daily_fortune: null, history: [historical] }),
  }));
  await page.route("**/api/heaven/trend/load", (route) => route.fulfill({
    contentType: "application/json",
    body: JSON.stringify({ ready: true, reading_id: 101, result: trendResult }),
  }));
  await page.route("**/api/heaven/fortune", (route) => route.fulfill({
    contentType: "application/json",
    body: JSON.stringify({ reused: false, reading: reading(102, "fortune", fortune) }),
  }));
  await page.route("**/api/heaven/heart/line", async (route) => {
    const payload = route.request().postDataJSON();
    const values = [...payload.values, payload.values.length % 2 ? 8 : 7];
    await route.fulfill({ contentType: "application/json", body: JSON.stringify({ position: values.length, value: values.at(-1), faces: ["front", "back", "front"], values }) });
  });
  await page.route("**/api/heaven/heart/complete", (route) => route.fulfill({
    contentType: "application/json",
    body: JSON.stringify({ reading_id: 103, result: { date: "2026-07-30", hexagram, notice: "仅供自我观察。" } }),
  }));
  await page.route("**/api/heaven/interpret", async (route) => {
    await new Promise((resolve) => setTimeout(resolve, 900));
    await route.fulfill({
      contentType: "application/x-ndjson",
      body: `${JSON.stringify({ type: "delta", content: "第一段解读" })}\n${JSON.stringify({ type: "delta", content: "，第二段解读" })}\n${JSON.stringify({ type: "done" })}\n`,
    });
  });
}

test("stage 11 Heaven workflows, animations and responsive layouts", async ({ page }) => {
  const consoleErrors = [];
  page.on("console", (message) => {
    if (message.type() === "error" && !message.text().includes("401 (Unauthorized)")) consoleErrors.push(message.text());
  });
  await mockHeaven(page);
  await authenticate(page, "stage4admin", "Stage4-pass-123!");
  await page.goto("/workspace/heaven");
  await page.getByRole("button", { name: "夜间" }).click();
  await expect(page.getByText("请输入股票代码或股票名称", { exact: true })).toBeVisible();
  await page.getByLabel("股票代码或名称").fill("贤丰控股");
  await page.getByRole("button", { name: "载入", exact: true }).click();
  await expect(page.getByText("当前标的：")).toContainText("贤丰控股");
  await expect(page.getByText("泰", { exact: true }).first()).toBeVisible();
  await page.getByRole("button", { name: "解势", exact: true }).click();
  const dialog = page.getByRole("dialog", { name: "解势" });
  await expect(dialog).toBeVisible();
  const box = await dialog.boundingBox();
  expect(box.width).toBeGreaterThan(700);
  expect(box.width / box.height).toBeGreaterThan(1.15);
  const loadingGeometry = await page.locator(".heaven-loading-stage").evaluate((stage) => {
    const canvas = stage.querySelector("canvas").getBoundingClientRect();
    const caption = stage.querySelector("p").getBoundingClientRect();
    return { canvasBottom: canvas.bottom, captionTop: caption.top };
  });
  expect(loadingGeometry.canvasBottom).toBeLessThanOrEqual(loadingGeometry.captionTop);
  await page.screenshot({ path: path.join(evidence, "heaven-interpret-loading-dark.jpg"), type: "jpeg", quality: 82 });
  await expect(page.getByText("第一段解读，第二段解读", { exact: true })).toBeVisible();
  await page.getByRole("button", { name: "历史记录", exact: true }).last().click();
  await page.getByRole("button", { name: /2026-07-30 · 贤丰控股/ }).last().click();
  await expect(page.getByText("历史解势内容", { exact: true })).toBeVisible();
  await dialog.getByRole("button", { name: "关闭" }).click();

  await page.locator(".heaven-mode-tabs button").filter({ hasText: "观气" }).click();
  await expect(page.getByText("湿热交蒸·燥中夹滞", { exact: true })).toBeVisible();
  await expect(page.getByText("壹", { exact: true })).toBeVisible();
  await page.locator(".heaven-section-toggle").click();
  await expect(page.getByText("行业一 · 行业二", { exact: true }).first()).toBeVisible();

  await page.clock.install();
  await page.locator(".heaven-mode-tabs button").filter({ hasText: "观心" }).click();
  const heartText = page.getByRole("heading", { name: "把所问之事留在心里" });
  const historyButton = page.getByRole("button", { name: "历史记录", exact: true }).first();
  const muteButton = page.getByRole("button", { name: "静音", exact: true });
  await expect(heartText).toBeVisible();
  expect(await contrastRatio(heartText)).toBeGreaterThanOrEqual(4.5);
  expect(await contrastRatio(historyButton)).toBeGreaterThanOrEqual(4.5);
  expect(await contrastRatio(muteButton)).toBeGreaterThanOrEqual(4.5);
  await page.getByRole("button", { name: "开始静心", exact: true }).click();
  const resetButton = page.getByRole("button", { name: "重新观心", exact: true });
  await expect(resetButton).toBeVisible();
  expect(await contrastRatio(resetButton)).toBeGreaterThanOrEqual(4.5);
  await page.clock.fastForward(1200);
  await expect(page.getByText("吸", { exact: true })).toBeVisible();
  await page.clock.fastForward(45_000);
  await page.getByRole("button", { name: "静心完成，开始起卦" }).click();
  await expect(page.locator(".heart-cast-line.is-revealed")).toHaveCount(0);
  await page.getByRole("button", { name: "投掷初爻" }).click();
  await expect(page.locator(".heart-cast-line.is-revealed")).toHaveCount(1);
  await expect(page.locator(".heart-cast-line").filter({ hasText: "未得" })).toHaveCount(5);
  expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBeLessThanOrEqual(0);
  await page.screenshot({ path: path.join(evidence, "heaven-dark-1920x1080.jpg"), type: "jpeg", quality: 82 });

  await page.getByRole("button", { name: "日间" }).click();
  await page.setViewportSize({ width: 390, height: 844 });
  expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBeLessThanOrEqual(0);
  await expect(page.locator(".mobile-nav")).toBeVisible();
  await page.screenshot({ path: path.join(evidence, "heaven-light-390x844.jpg"), type: "jpeg", quality: 82 });
  expect(consoleErrors).toEqual([]);
});

test("nonmembers retain the complete grey Heaven structure", async ({ page }) => {
  await mockHeaven(page);
  await authenticate(page, "stage4user", "Stage4-user-123!");
  await page.goto("/workspace/heaven");
  await expect(page.getByText("问天仅对会员开放")).toBeVisible();
  await expect(page.locator(".heaven-mode-tabs").getByText("观势", { exact: true })).toBeVisible();
  await expect(page.getByLabel("股票代码或名称")).toBeDisabled();
  await expect(page.locator(".locked-content")).toBeVisible();
});
