import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import test from 'node:test';
import {
  analyzeChatMessageForSave,
  buildChatSavePreviewFrameUrl,
  buildChatSaveThumbnailUrl,
  buildWorkspaceAssetUrl,
  buildWorkspaceBaseHref,
  buildWorkspaceThumbnailUrl,
  extractStaticPageLinks,
  findPublishHtml,
  injectHtmlBaseHref,
  resolveClosestHtmlRelativePath,
  resolveChatSaveAnalysis,
  sanitizeMessageContentForSave,
} from './mindspace-chat-save.mjs';

const USER_ID = 'a6fb1e97-2b0f-447b-b138-4561d8e5c53e';

test('extractStaticPageLinks finds user-owned MindSpace html links', () => {
  const content = `
页面已完成！
https://m.tkmind.cn/MindSpace/${USER_ID}/mapo-tofu.html
`;
  const links = extractStaticPageLinks(content, { userId: USER_ID });
  assert.equal(links.length, 1);
  assert.equal(links[0].filename, 'mapo-tofu.html');
  assert.equal(links[0].relativePath, 'public/mapo-tofu.html');
  assert.equal(links[0].publicUrl, `https://m.tkmind.cn/MindSpace/${USER_ID}/public/mapo-tofu.html`);
});

test('extractStaticPageLinks ignores other users', () => {
  const content = 'https://m.tkmind.cn/MindSpace/other-id/report.html';
  const links = extractStaticPageLinks(content, { userId: USER_ID });
  assert.equal(links.length, 0);
});

test('extractStaticPageLinks accepts legacy username urls when username provided', () => {
  const content = 'https://goo.tkmind.cn/MindSpace/john/report.html';
  const links = extractStaticPageLinks(content, { username: 'john' });
  assert.equal(links.length, 1);
  assert.equal(links[0].relativePath, 'public/report.html');
  assert.equal(links[0].publicUrl, 'https://goo.tkmind.cn/MindSpace/john/public/report.html');
});

test('extractStaticPageLinks accepts uuid links when both user id and username are provided', () => {
  const content = `https://goo.tkmind.cn/MindSpace/${USER_ID}/public/report.html`;
  const links = extractStaticPageLinks(content, { userId: USER_ID, username: 'john' });
  assert.equal(links.length, 1);
  assert.equal(links[0].relativePath, 'public/report.html');
});

test('extractStaticPageLinks accepts legacy username links when user id is available', () => {
  const content = 'https://goo.tkmind.cn/MindSpace/john/report.html';
  const links = extractStaticPageLinks(content, { userId: USER_ID, username: 'john' });
  assert.equal(links.length, 1);
  assert.equal(links[0].publicUrl, 'https://goo.tkmind.cn/MindSpace/john/public/report.html');
});

test('analyzeChatMessageForSave prefers static html mode', () => {
  const analysis = analyzeChatMessageForSave({
    content: `链接 https://m.tkmind.cn/MindSpace/${USER_ID}/report.html`,
    userId: USER_ID,
    username: 'john',
    h5Root: '/tmp/h5',
  });
  assert.equal(analysis.contentMode, 'static_html');
  assert.equal(analysis.filename, 'report.html');
  assert.match(analysis.suggestedTitle, /report/i);
});

test('analyzeChatMessageForSave falls back to markdown article', () => {
  const analysis = analyzeChatMessageForSave({
    content: '这是一段普通 AI 回答，没有页面链接。',
    userId: USER_ID,
    username: 'john',
    h5Root: '/tmp/h5',
  });
  assert.equal(analysis.contentMode, 'markdown');
  assert.equal(analysis.links.length, 0);
  assert.match(analysis.suggestedTitle, /普通 AI 回答/);
});

test('buildWorkspaceAssetUrl and buildWorkspaceThumbnailUrl', () => {
  assert.equal(
    buildWorkspaceAssetUrl(USER_ID, 'mapo-tofu.html'),
    `/MindSpace/${USER_ID}/mapo-tofu.html`,
  );
  assert.equal(
    buildWorkspaceThumbnailUrl(USER_ID, 'reports/guide.html'),
    `/MindSpace/${USER_ID}/reports/guide.thumbnail.svg`,
  );
});

test('buildChatSavePreviewUrls use local api routes', () => {
  assert.match(
    buildChatSavePreviewFrameUrl({
      sessionId: 'sess-1',
      messageId: 'msg-1',
      selectedLinkIndex: 2,
    }),
    /^\/api\/mindspace\/v1\/pages\/chat-save-preview\?/,
  );
  assert.match(
    buildChatSaveThumbnailUrl({
      sessionId: 'sess-1',
      messageId: 'msg-1',
      previewTitle: '标题',
    }),
    /chat-save-thumbnail\?.*preview_title=%E6%A0%87%E9%A2%98/,
  );
});

test('findPublishHtml resolves nested public html by basename', async () => {
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-chat-save-'));
  const publishDir = path.join(root, 'MindSpace', USER_ID, 'public');
  await fs.mkdir(publishDir, { recursive: true });
  await fs.writeFile(
    path.join(publishDir, 'welcome.html'),
    '<!DOCTYPE html><html><head><title>Welcome</title></head><body>hi</body></html>',
    'utf8',
  );
  const loaded = await findPublishHtml(root, USER_ID, 'welcome.html');
  assert.equal(loaded.relativePath, 'public/welcome.html');
  assert.match(loaded.content, /Welcome/);
});

test('findPublishHtml resolves close html filename typos when match is unique', async () => {
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-chat-save-typo-'));
  const publishDir = path.join(root, 'MindSpace', USER_ID, 'public');
  await fs.mkdir(publishDir, { recursive: true });
  await fs.writeFile(
    path.join(publishDir, 'memind-deep-analysis.html'),
    '<!DOCTYPE html><html><head><title>Deep Analysis</title></head><body>ok</body></html>',
    'utf8',
  );
  const loaded = await findPublishHtml(root, USER_ID, 'public/memind-dep-analysis.html');
  assert.equal(loaded.relativePath, 'public/memind-deep-analysis.html');
  assert.match(loaded.content, /Deep Analysis/);
});

test('resolveClosestHtmlRelativePath ignores ambiguous typo matches', async () => {
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-chat-save-ambiguous-'));
  await fs.mkdir(path.join(root, 'public'), { recursive: true });
  await fs.writeFile(path.join(root, 'public', 'mindmap-plan.html'), '<html></html>', 'utf8');
  await fs.writeFile(path.join(root, 'public', 'mindmap-play.html'), '<html></html>', 'utf8');
  const resolved = await resolveClosestHtmlRelativePath(root, 'public/mindmap-plab.html');
  assert.equal(resolved, null);
});

test('injectHtmlBaseHref adds base tag for relative assets', () => {
  const html = '<html><head><title>x</title></head><body></body></html>';
  const next = injectHtmlBaseHref(html, buildWorkspaceBaseHref(USER_ID, 'public/page.html'));
  assert.match(next, /<base href="\/MindSpace\//);
});

test('sanitizeMessageContentForSave repairs duplicated streaming urls', () => {
  const raw =
    'httpshttps://://gg22.t.tkmkmindind.cn.cn/M/MindSpace/a6fb1e97/public/public/w/welcomeelcome-v-v22.html.html';
  const cleaned = sanitizeMessageContentForSave(raw);
  assert.doesNotMatch(cleaned, /httpshttps/);
  assert.match(cleaned, /https:\/\//);
});

test('resolveChatSaveAnalysis falls back to local html filename hints', async () => {
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-chat-save-hint-'));
  const publishDir = path.join(root, 'MindSpace', USER_ID, 'public');
  await fs.mkdir(publishDir, { recursive: true });
  await fs.writeFile(
    path.join(publishDir, 'welcome-v2.html'),
    '<!DOCTYPE html><html><head><title>Welcome v2</title></head><body>hi</body></html>',
    'utf8',
  );
  const corrupted =
    '请看 welcomeelcome-v-v22.html.html，链接可能坏了 httpshttps://://broken.example/MindSpace/other/report.html';
  const result = await resolveChatSaveAnalysis({
    content: corrupted,
    userId: USER_ID,
    username: 'john',
    h5Root: root,
  });
  assert.equal(result.analysis.contentMode, 'static_html');
  assert.equal(result.resolvedHtml?.relativePath, 'public/welcome-v2.html');
});
