#!/usr/bin/env node
/**
 * 通过 goose 子会话重新生成 MindSpace 页面内容（Studio / RDS 环境测试）
 *
 * 用法：
 *   node scripts/regenerate-page-goose-test.mjs [pageId] [parentSessionId]
 *
 * 默认：探索世界 · TKMind（john，source_session 20260614_70）
 */
import crypto from 'node:crypto';
import fs from 'node:fs';
import path from 'node:path';
import { Readable } from 'node:stream';
import { fileURLToPath } from 'node:url';
import { Agent, fetch as undiciFetch } from 'undici';
import { createDbPool } from '../db.mjs';
import { createUserAuth } from '../user-auth.mjs';
import { createPageService } from '../mindspace-pages.mjs';
import { createPageLiveEditService } from '../mindspace-page-live-edit.mjs';
import { createPageEditSessionService } from '../mindspace-page-edit-session.mjs';
import { createLlmProviderService } from '../llm-providers.mjs';
import { extractMindSpacePagePatch } from '../mindspace-page-patch.mjs';
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');

function loadEnvFile(filePath) {
  if (!fs.existsSync(filePath)) return;
  for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) continue;
    const eq = trimmed.indexOf('=');
    if (eq < 0) continue;
    const key = trimmed.slice(0, eq).trim();
    const value = trimmed.slice(eq + 1).trim();
    if (!process.env[key]) process.env[key] = value;
  }
}

loadEnvFile(path.join(root, '.env'));

const PAGE_ID = process.argv[2] ?? '44a8d4f5-7dda-4e0c-973a-c580bf2cb82b';
const PARENT_SESSION = process.argv[3] ?? '20260614_70';
const USERNAME = 'john';
const apiTarget = process.env.TKMIND_API_TARGET ?? 'https://127.0.0.1:18006';
const apiSecret = process.env.TKMIND_SERVER__SECRET_KEY ?? '';
const h5ApiBase = (process.env.H5_PAGE_PATCH_BASE ?? 'http://127.0.0.1:8081').replace(/\/$/, '');
const insecureDispatcher = new Agent({ connect: { rejectUnauthorized: false } });

function isHttpsTarget(target) {
  return target.startsWith('https://');
}

function createApiFetch() {
  return async (pathname, init = {}) => {
    const url = new URL(pathname, apiTarget);
    const headers = {
      ...(init.headers ?? {}),
      'X-Secret-Key': apiSecret,
    };
    if (init.body && !headers['Content-Type']) {
      headers['Content-Type'] = 'application/json';
    }
    return undiciFetch(url, {
      ...init,
      headers,
      dispatcher: isHttpsTarget(apiTarget) ? insecureDispatcher : undefined,
    });
  };
}

async function executeSessionReply(apiFetch, sessionId, requestId, prompt) {
  const eventsResponse = await apiFetch(`/sessions/${sessionId}/events`, {
    method: 'GET',
    headers: { Accept: 'text/event-stream' },
  });
  if (!eventsResponse.ok || !eventsResponse.body) {
    const text = await eventsResponse.text().catch(() => '');
    throw new Error(text || '无法建立事件流');
  }

  const replyResponse = await apiFetch(`/sessions/${sessionId}/reply`, {
    method: 'POST',
    body: JSON.stringify({
      request_id: requestId,
      user_message: {
        role: 'user',
        created: Date.now(),
        content: [{ type: 'text', text: prompt }],
        metadata: { userVisible: true, agentVisible: true },
      },
    }),
  });
  if (!replyResponse.ok) {
    const text = await replyResponse.text().catch(() => '');
    throw new Error(text || 'reply 失败');
  }
  replyResponse.body?.cancel?.();

  const reader = Readable.fromWeb(eventsResponse.body);
  const decoder = new TextDecoder();
  let buffer = '';
  let messages = [];

  const pushMessage = (list, message) => {
    const idx = list.findIndex((item) => item.id === message.id);
    if (idx >= 0) {
      const next = [...list];
      next[idx] = message;
      return next;
    }
    return [...list, message];
  };

  const messageVisibleText = (message) =>
    (message?.content ?? [])
      .filter((item) => item.type === 'text')
      .map((item) => item.text)
      .join('\n')
      .trim();

  for await (const chunk of reader) {
    buffer += decoder.decode(chunk, { stream: true });
    const frames = buffer.split('\n\n');
    buffer = frames.pop() ?? '';
    for (const frame of frames) {
      let data = '';
      for (const line of frame.split('\n')) {
        if (line.startsWith('data:')) data += line.slice(5).trim();
      }
      if (!data) continue;
      let event;
      try {
        event = JSON.parse(data);
      } catch {
        continue;
      }
      const routingId = event.chat_request_id ?? event.request_id;
      if (routingId && routingId !== requestId) continue;

      if (event.type === 'Message' && event.message?.metadata?.userVisible) {
        messages = pushMessage(messages, event.message);
      } else if (event.type === 'UpdateConversation') {
        messages = (event.conversation ?? []).filter((item) => item.metadata?.userVisible);
      } else if (event.type === 'Error') {
        throw new Error(event.error || 'goose 执行失败');
      } else if (event.type === 'Finish') {
        const assistantTexts = messages
          .filter((item) => item.role === 'assistant')
          .map((item) => messageVisibleText(item))
          .filter(Boolean);
        const combined = assistantTexts.join('\n\n');
        const withPatch = [...assistantTexts].reverse().find((text) => text.includes('mindspace-page-update'));
        return { text: withPatch ?? combined ?? messageVisibleText([...messages].reverse().find((item) => item.role === 'assistant')) };
      }
    }
  }
  throw new Error('goose 回复未完成');
}

async function main() {
  const pool = createDbPool();
  const userAuth = createUserAuth(pool, { h5Root: root });
  const pageService = createPageService(pool, {
    h5Root: root,
    storageRoot: process.env.MINDSPACE_STORAGE_ROOT ?? path.join(root, 'data', 'mindspace'),
  });
  const pageLiveEdit = createPageLiveEditService({
    pageService,
    resolveUserIdForAgentSession: async (sessionId) => {
      const [rows] = await pool.query(
        `SELECT user_id FROM h5_user_sessions WHERE agent_session_id = ? LIMIT 1`,
        [sessionId],
      );
      return rows[0]?.user_id ?? null;
    },
  });
  const llmProviderService = createLlmProviderService(pool, {
    apiTarget,
    apiSecret,
    encryptionKey:
      process.env.H5_SETTINGS_ENCRYPTION_KEY ?? process.env.TKMIND_SERVER__SECRET_KEY ?? '',
  });
  const pageEditSession = createPageEditSessionService({
    apiTarget,
    apiSecret,
    userAuth,
    pageService,
    pageLiveEdit,
    llmProviderService,
  });
  const apiFetch = createApiFetch();

  const [userRows] = await pool.query(`SELECT id FROM h5_users WHERE username = ? LIMIT 1`, [
    USERNAME,
  ]);
  const userId = userRows[0]?.id;
  if (!userId) throw new Error(`用户 ${USERNAME} 不存在`);

  const pageBefore = await pageService.getPage(userId, PAGE_ID);
  console.log('目标页面:', pageBefore.title, `(v${pageBefore.versionNo})`);
  console.log('父 goose 会话:', PARENT_SESSION);

  const forked = await pageEditSession.forkSession({
    userId,
    pageId: PAGE_ID,
    parentSessionId: PARENT_SESSION,
    h5ApiBase,
  });
  console.log('✓ 子会话已 fork:', forked.sessionId);

  const contentPreview = String(pageBefore.content ?? '').slice(0, 12000);
  const prompt = `请基于下方【当前页面 HTML】全面升级为更精美的旅行主题落地页：
- 深色沉浸式 Hero + 玻璃拟态卡片 + 渐变强调文字
- 保留瑞士、马尔代夫、京都三个目的地
- 必须包含 mindspace-cover meta 与完整内联 CSS（CSP 安全，禁止外部 JS）
- 标题「探索世界 · TKMind」，summary 写一句精炼中文

**禁止**读写工作区文件。完成后**只**在回复末尾输出一个 \`\`\`mindspace-page-update\`\`\` 代码块（JSON：title、summary、content 完整 HTML）。

【当前页面 HTML】
${contentPreview}`;

  const requestId = crypto.randomUUID();
  console.log('→ 向 goose 发送重生成指令…');
  const reply = await executeSessionReply(apiFetch, forked.sessionId, requestId, prompt);
  console.log('✓ goose 回复完成，文本长度:', reply.text.length);
  console.log(reply.text.slice(-1200));

  let pageAfter = await pageService.getPage(userId, PAGE_ID);
  let changed =
    pageAfter.versionNo !== pageBefore.versionNo ||
    pageAfter.updatedAt !== pageBefore.updatedAt ||
    pageAfter.content !== pageBefore.content;

  if (!changed) {
    const patch = extractMindSpacePagePatch(reply.text);
    if (patch) {
      console.log('→ 从 mindspace-page-update 块应用补丁…');
      await pageLiveEdit.applyAgentPatch({
        sessionId: forked.sessionId,
        pageId: PAGE_ID,
        ...patch,
        changeNote: 'goose 重生成精美旅行页',
      });
      pageAfter = await pageService.getPage(userId, PAGE_ID);
      changed =
        pageAfter.versionNo !== pageBefore.versionNo ||
        pageAfter.updatedAt !== pageBefore.updatedAt ||
        pageAfter.content !== pageBefore.content;
    }
  }

  console.log('\n结果:');
  console.log('  版本:', pageBefore.versionNo, '→', pageAfter.versionNo);
  console.log('  摘要:', pageAfter.summary?.slice(0, 120));
  console.log('  内容已变更:', changed ? '是' : '否');

  const publicBase = (process.env.H5_PUBLIC_BASE_URL ?? 'https://58.38.22.103').replace(/\/$/, '');
  const [pubRows] = await pool.query(
    `SELECT url_slug, status FROM h5_publish_records WHERE id = (SELECT current_publish_id FROM h5_page_records WHERE id = ?)`,
    [PAGE_ID],
  );
  const slug = pubRows[0]?.url_slug;
  if (slug) {
    console.log('  公开预览:', `${publicBase}/p/${slug}`);
  }

  await pageEditSession.closeSession({
    userId,
    sessionId: forked.sessionId,
    pageId: PAGE_ID,
    parentSessionId: PARENT_SESSION,
    summary: '已通过子会话重生成旅行主题页视觉。',
  });

  await pool.end();
  if (!changed) {
    console.error('\n⚠ 页面内容未检测到变更，请检查 goose 是否调用了 mindspace_page_patch');
    process.exit(1);
  }
  console.log('\n✅ 测试完成');
}

main().catch((error) => {
  console.error(error instanceof Error ? error.stack : error);
  process.exit(1);
});
