#!/usr/bin/env node
/**
 * john 账号水果主题 E2E（仅本地）：工作区 HTML → 预览图 → 保存到空间 → 可点击链接
 * 用法：node scripts/fruit-theme-john-e2e.mjs
 * 环境：自动启动本地 server（MINDSPACE_E2E_PORT）；勿对生产 URL 跑本脚本
 */
import assert from 'node:assert/strict';
import { spawn } from 'node:child_process';
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { loadH5Environment } from './load-env.mjs';
import { createDbPool } from '../db.mjs';
import { createUserAuth } from '../user-auth.mjs';
import { buildPublicUrl } from '../user-publish.mjs';
import {
  ensureWorkspaceHtmlThumbnail,
  workspaceThumbnailRelativePath,
} from '../mindspace-workspace-thumbnails.mjs';
import { isModernFeedThumbnail } from '../mindspace-thumbnails.mjs';

const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
loadH5Environment(import.meta.dirname);

if (/go\.tkmind\.cn|goo\.tkmind\.cn|120\.26\.184\.105/i.test(process.env.BASE_URL ?? '')) {
  throw new Error('本脚本仅用于本地验证，请勿设置生产 BASE_URL');
}

const portalPort = Number(process.env.MINDSPACE_E2E_PORT ?? 18140);
const BASE_URL = `http://127.0.0.1:${portalPort}`;
const HTML_NAME = 'fruit-theme-test.html';
const USERNAME = 'john';
const JOHN_PASSWORD = process.env.JOHN_PASSWORD ?? process.env.H5_ACCESS_PASSWORD ?? '981122tj';
const publishDir = path.join(root, 'MindSpace', USERNAME);
const htmlPath = path.join(publishDir, HTML_NAME);
const thumbRel = workspaceThumbnailRelativePath(HTML_NAME);
const publicPageUrl = buildPublicUrl(BASE_URL, USERNAME, HTML_NAME);
const publicThumbUrl = buildPublicUrl(BASE_URL, USERNAME, thumbRel);
const agentReplyLink = `[夏日鲜果指南 · 水果主题测试](${publicPageUrl})`;

const portal = spawn(process.execPath, ['server.mjs'], {
  cwd: root,
  env: {
    ...process.env,
    H5_PORT: String(portalPort),
    H5_PUBLIC_BASE_URL: BASE_URL,
    TKMIND_API_TARGET: 'http://127.0.0.1:9',
  },
  stdio: ['ignore', 'pipe', 'pipe'],
});
let portalLogs = '';
portal.stdout.on('data', (chunk) => {
  portalLogs += chunk.toString();
});
portal.stderr.on('data', (chunk) => {
  portalLogs += chunk.toString();
});

async function waitForPortal() {
  for (let attempt = 0; attempt < 80; attempt += 1) {
    if (portal.exitCode != null) throw new Error(`本地 server 提前退出\n${portalLogs}`);
    try {
      const response = await fetch(`${BASE_URL}/auth/status`);
      if (response.ok) return;
    } catch {
      // still starting
    }
    await new Promise((resolve) => setTimeout(resolve, 150));
  }
  throw new Error(`本地 server 启动超时\n${portalLogs}`);
}

function cookieHeader(setCookie) {
  if (!setCookie) return '';
  const parts = Array.isArray(setCookie) ? setCookie : [setCookie];
  return parts.map((c) => c.split(';')[0]).join('; ');
}

async function request(pathname, { method = 'GET', body, cookie } = {}) {
  const headers = {};
  if (body) headers['Content-Type'] = 'application/json';
  if (cookie) headers.Cookie = cookie;
  const response = await fetch(`${BASE_URL}${pathname}`, { method, headers, body: body ? JSON.stringify(body) : undefined });
  const type = response.headers.get('content-type') ?? '';
  const payload = type.includes('json') ? await response.json() : await response.text();
  return { response, payload, setCookie: response.headers.getSetCookie?.() ?? response.headers.get('set-cookie') };
}

async function ensureJohnPassword() {
  const pool = createDbPool();
  const auth = createUserAuth(pool, { h5Root: root });
  let login = await auth.login({ username: USERNAME, password: JOHN_PASSWORD, ip: '127.0.0.1' });
  if (!login.ok) {
    const [rows] = await pool.query(`SELECT id, email FROM h5_users WHERE username = ? LIMIT 1`, [
      USERNAME,
    ]);
    const user = rows[0];
    if (!user) throw new Error('本地数据库无 john 用户，请先注册或导入数据');
    const email = user.email ?? `${USERNAME}@local.test`;
    if (!user.email) {
      await pool.query(`UPDATE h5_users SET email = ? WHERE id = ?`, [email, user.id]);
    }
    const reset = await auth.resetPassword({ username: USERNAME, email, password: JOHN_PASSWORD });
    assert.equal(reset.ok, true, reset.message ?? '重置 john 本地密码失败');
    login = await auth.login({ username: USERNAME, password: JOHN_PASSWORD, ip: '127.0.0.1' });
  }
  assert.equal(login.ok, true, login.error ?? 'john 本地登录失败');
  const { response, setCookie } = await request('/auth/login', {
    method: 'POST',
    body: { username: USERNAME, password: JOHN_PASSWORD },
  });
  assert.equal(response.status, 200, 'john HTTP 登录应成功');
  await pool.end();
  return cookieHeader(setCookie);
}

async function main() {
  console.log('=== john 水果主题 E2E（本地） ===');
  await waitForPortal();
  console.log(`BASE_URL: ${BASE_URL}`);

  const html = await fs.readFile(htmlPath, 'utf8');
  assert.match(html, /mindspace-cover/, 'HTML 应包含 mindspace-cover');

  const svg = await ensureWorkspaceHtmlThumbnail(publishDir, HTML_NAME, html, {
    title: '夏日鲜果指南',
    subtitle: '水果主题测试',
  });
  assert.equal(isModernFeedThumbnail(svg), true, '工作区预览图应为新版 3:4');
  assert.match(svg, /美食|鲜果|FRUIT/i, '预览图应体现水果/美食主题');
  const hasPhoto = /preserveAspectRatio="xMidYMid slice"/.test(svg);
  console.log(`✓ 工作区预览图已生成: ${thumbRel}（含主图: ${hasPhoto ? '是' : '否'}）`);

  const pageCheck = await request(`/MindSpace/${USERNAME}/${HTML_NAME}`);
  assert.equal(pageCheck.response.status, 200, `公网 HTML 应可访问: ${publicPageUrl}`);
  console.log(`✓ 公网 HTML 200: ${publicPageUrl}`);

  const thumbCheck = await request(`/MindSpace/${USERNAME}/${thumbRel}`);
  assert.equal(thumbCheck.response.status, 200, `公网预览图应可访问: ${publicThumbUrl}`);
  assert.match(String(thumbCheck.payload), /width="540" height="720"/, '线上预览图为 3:4');
  console.log(`✓ 公网预览图 200: ${publicThumbUrl}`);

  assert.match(agentReplyLink, /^\[.+\]\(https?:\/\/.+\)$/);
  console.log(`✓ Agent 应回复的可点击链接:\n  ${agentReplyLink}`);

  const cookie = await ensureJohnPassword();
  console.log('✓ john 本地登录成功');

  const { response: spaceRes, payload: spacePayload } = await request('/api/mindspace/v1/space', {
    cookie,
  });
  assert.equal(spaceRes.status, 200, JSON.stringify(spacePayload));

  const saveBody = {
    title: '夏日鲜果指南 · 水果主题测试',
    summary: 'TKMind 水果主题预览图 E2E',
    content: html,
    content_format: 'html',
    page_type: 'html',
    category_code: 'draft',
  };
  const created = await request('/api/mindspace/v1/pages', {
    method: 'POST',
    body: saveBody,
    cookie,
  });
  assert.equal(created.response.status, 201, JSON.stringify(created.payload));
  const pageId = created.payload?.data?.id ?? created.payload?.data?.page?.id;
  assert.ok(pageId, '应创建页面记录');

  await new Promise((r) => setTimeout(r, 800));

  const thumbApi = await request(`/api/mindspace/v1/pages/${pageId}/thumbnail`, { cookie });
  assert.equal(thumbApi.response.status, 200, '页面缩略图 API 应返回 200');
  assert.match(String(thumbApi.payload), /width="540" height="720"/);
  console.log(`✓ 我的空间缩略图 API 200: /api/mindspace/v1/pages/${pageId}/thumbnail`);

  console.log('\n=== 全部通过 ===');
}

try {
  await main();
} finally {
  portal.kill('SIGTERM');
}
