import test from 'node:test';
import assert from 'node:assert/strict';
import { randomUUID } from 'node:crypto';

process.env.NODE_ENV = 'test';
process.env.DB_PATH = ':memory:';

const jsonFetch = async (
  baseUrl: string,
  path: string,
  options?: { method?: string; body?: unknown },
) => {
  const res = await fetch(`${baseUrl}${path}`, {
    method: options?.method ?? 'GET',
    headers: options?.body ? { 'Content-Type': 'application/json' } : undefined,
    body: options?.body ? JSON.stringify(options.body) : undefined,
  });

  const text = await res.text();
  let json: any = null;
  try {
    json = text ? JSON.parse(text) : null;
  } catch {
    json = null;
  }
  return { status: res.status, json, text };
};

test('题库文本导入增量模式按内容覆盖', async () => {
  const { initDatabase, run, get } = await import('../api/database');
  await initDatabase();

  const { app } = await import('../api/server');
  const server = app.listen(0);

  try {
    const addr = server.address();
    assert.ok(addr && typeof addr === 'object');
    const baseUrl = `http://127.0.0.1:${addr.port}`;

    const oldId = randomUUID();
    await run(
      `INSERT INTO questions (id, content, type, options, answer, score, category)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [oldId, '重复题目', 'single', JSON.stringify(['A', 'B']), 'A', 5, '通用'],
    );

    const res = await jsonFetch(baseUrl, '/api/questions/import-text', {
      method: 'POST',
      body: {
        mode: 'incremental',
        questions: [
          {
            content: '重复题目',
            type: 'multiple',
            category: '数学',
            options: ['选项A', '选项B', '选项C'],
            answer: ['选项A', '选项C'],
            analysis: '解析：这是一道示例题',
            score: 10,
          },
        ],
      },
    });

    assert.equal(res.status, 200);
    assert.equal(res.json?.success, true);
    assert.equal(res.json?.data?.inserted, 0);
    assert.equal(res.json?.data?.updated, 1);

    const row = await get(`SELECT * FROM questions WHERE content = ?`, ['重复题目']);
    assert.equal(row.id, oldId);
    assert.equal(row.type, 'multiple');
    assert.equal(row.category, '数学');
    assert.equal(row.score, 10);
    assert.equal(row.analysis, '解析：这是一道示例题');
    assert.equal(JSON.parse(row.options).length, 3);
    assert.deepEqual(JSON.parse(row.answer), ['选项A', '选项C']);
  } finally {
    await new Promise<void>((resolve) => server.close(() => resolve()));
  }
});

test('题库文本导入覆盖模式清空题库与答题记录', async () => {
  const { initDatabase, run, get } = await import('../api/database');
  await initDatabase();

  const { app } = await import('../api/server');
  const server = app.listen(0);

  try {
    const addr = server.address();
    assert.ok(addr && typeof addr === 'object');
    const baseUrl = `http://127.0.0.1:${addr.port}`;

    const userId = randomUUID();
    const subjectId = randomUUID();
    const oldQuestionId = randomUUID();
    const recordId = randomUUID();
    const answerId = randomUUID();

    await run(`INSERT INTO users (id, name, phone, password) VALUES (?, ?, ?, ?)`, [
      userId,
      '测试用户',
      `138${Math.floor(Math.random() * 1e8).toString().padStart(8, '0')}`,
      '',
    ]);

    await run(
      `INSERT INTO exam_subjects (id, name, type_ratios, category_ratios, total_score, duration_minutes)
       VALUES (?, ?, ?, ?, ?, ?)`,
      [
        subjectId,
        '测试科目',
        JSON.stringify({ single: 100 }),
        JSON.stringify({ 通用: 100 }),
        100,
        60,
      ],
    );

    await run(
      `INSERT INTO questions (id, content, type, options, answer, score, category)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [oldQuestionId, '旧题目', 'single', JSON.stringify(['A', 'B']), 'A', 5, '通用'],
    );

    await run(
      `INSERT INTO quiz_records (id, user_id, subject_id, task_id, total_score, correct_count, total_count, created_at)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
      [recordId, userId, subjectId, null, 5, 1, 1, new Date().toISOString()],
    );

    await run(
      `INSERT INTO quiz_answers (id, record_id, question_id, user_answer, score, is_correct, created_at)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [answerId, recordId, oldQuestionId, 'A', 5, 1, new Date().toISOString()],
    );

    const res = await jsonFetch(baseUrl, '/api/questions/import-text', {
      method: 'POST',
      body: {
        mode: 'overwrite',
        questions: [
          {
            content: '新题目',
            type: 'single',
            category: '通用',
            options: ['A', 'B'],
            answer: 'A',
            analysis: '解析：新题目的说明',
            score: 5,
          },
        ],
      },
    });

    assert.equal(res.status, 200);
    assert.equal(res.json?.success, true);
    assert.equal(res.json?.data?.inserted, 1);
    assert.equal(res.json?.data?.updated, 0);

    const questionCount = await get(`SELECT COUNT(*) as total FROM questions`);
    const recordCount = await get(`SELECT COUNT(*) as total FROM quiz_records`);
    const answerCount = await get(`SELECT COUNT(*) as total FROM quiz_answers`);

    assert.equal(questionCount.total, 1);
    assert.equal(recordCount.total, 0);
    assert.equal(answerCount.total, 0);

    const row = await get(`SELECT * FROM questions WHERE content = ?`, ['新题目']);
    assert.equal(row.analysis, '解析：新题目的说明');
  } finally {
    await new Promise<void>((resolve) => server.close(() => resolve()));
  }
});

test('答题记录详情应返回题目解析字段', async () => {
  const { initDatabase, run } = await import('../api/database');
  await initDatabase();

  const { app } = await import('../api/server');
  const server = app.listen(0);

  try {
    const addr = server.address();
    assert.ok(addr && typeof addr === 'object');
    const baseUrl = `http://127.0.0.1:${addr.port}`;

    const userId = randomUUID();
    const questionId = randomUUID();
    const recordId = randomUUID();
    const answerId = randomUUID();
    const createdAt = new Date().toISOString();

    await run(`INSERT INTO users (id, name, phone, password) VALUES (?, ?, ?, ?)`, [
      userId,
      '测试用户',
      '13800138000',
      '',
    ]);

    await run(
      `INSERT INTO questions (id, content, type, options, answer, analysis, score, category)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
      [questionId, '带解析题目', 'single', JSON.stringify(['A', 'B']), 'A', '解析内容', 5, '通用'],
    );

    await run(
      `INSERT INTO quiz_records (id, user_id, subject_id, task_id, total_score, correct_count, total_count, created_at)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
      [recordId, userId, null, null, 5, 1, 1, createdAt],
    );

    await run(
      `INSERT INTO quiz_answers (id, record_id, question_id, user_answer, score, is_correct, created_at)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [answerId, recordId, questionId, 'A', 5, 1, createdAt],
    );

    const res = await jsonFetch(baseUrl, `/api/quiz/records/detail/${recordId}`);
    assert.equal(res.status, 200);
    assert.equal(res.json?.success, true);
    assert.equal(res.json?.data?.record?.id, recordId);
    assert.equal(Array.isArray(res.json?.data?.answers), true);
    assert.equal(res.json?.data?.answers?.[0]?.questionAnalysis, '解析内容');
  } finally {
    await new Promise<void>((resolve) => server.close(() => resolve()));
  }
});

test('前端文本解析支持 | 分隔格式', async () => {
  const { parseTextQuestions } = await import('../src/utils/questionTextImport');

  const input = [
    '题型|题目类别|分值|题目内容|选项|答案|解析',
    '单选|通用|5|我国首都是哪里?|北京|上海|广州|深圳|A|我国首都为北京',
    '多选|通用|5|以下哪些是水果?|苹果|白菜|香蕉|西红柿|A,C,D|水果包括苹果/香蕉/西红柿',
    '判断|通用|0|地球是圆的||正确|地球接近球体',
  ].join('\n');

  const res = parseTextQuestions(input);
  assert.deepEqual(res.errors, []);
  assert.equal(res.questions.length, 3);

  const single = res.questions.find((q: any) => q.type === 'single');
  assert.ok(single);
  assert.deepEqual(single.options, ['北京', '上海', '广州', '深圳']);
  assert.equal(single.answer, '北京');
  assert.equal(single.analysis, '我国首都为北京');

  const multiple = res.questions.find((q: any) => q.type === 'multiple');
  assert.ok(multiple);
  assert.deepEqual(multiple.options, ['苹果', '白菜', '香蕉', '西红柿']);
  assert.deepEqual(multiple.answer, ['苹果', '香蕉', '西红柿']);
  assert.equal(multiple.analysis, '水果包括苹果/香蕉/西红柿');

  const judgment = res.questions.find((q: any) => q.type === 'judgment');
  assert.ok(judgment);
  assert.equal(judgment.answer, '正确');
  assert.equal(judgment.analysis, '地球接近球体');
  assert.equal(judgment.score, 0);
});

test('前端文本解析：| 分隔时选项允许包含逗号/顿号', async () => {
  const { parseTextQuestions } = await import('../src/utils/questionTextImport');

  const input = [
    '题型|题目类别|分值|题目内容|选项|答案|解析',
    '单选|通用|5|带标点的选项是否应完整保留?|选项A，包含中文逗号|选项B、包含顿号|选项C(括号)|选项D。句号|A|应能正常解析',
  ].join('\n');

  const res = parseTextQuestions(input);
  assert.deepEqual(res.errors, []);
  assert.equal(res.questions.length, 1);

  const q = res.questions[0];
  assert.equal(q.type, 'single');
  assert.deepEqual(q.options, ['选项A，包含中文逗号', '选项B、包含顿号', '选项C(括号)', '选项D。句号']);
  assert.equal(q.answer, '选项A，包含中文逗号');
  assert.equal(q.analysis, '应能正常解析');
});

test('题库文本导入应允许0分题目', async () => {
  const { initDatabase, get } = await import('../api/database');
  await initDatabase();

  const { app } = await import('../api/server');
  const server = app.listen(0);

  try {
    const addr = server.address();
    assert.ok(addr && typeof addr === 'object');
    const baseUrl = `http://127.0.0.1:${addr.port}`;

    const res = await jsonFetch(baseUrl, '/api/questions/import-text', {
      method: 'POST',
      body: {
        mode: 'incremental',
        questions: [
          {
            content: '0分判断题示例',
            type: 'judgment',
            category: '通用',
            options: undefined,
            answer: '正确',
            analysis: '该题用于验证0分允许导入',
            score: 0,
          },
        ],
      },
    });

    assert.equal(res.status, 200);
    assert.equal(res.json?.success, true);
    assert.equal(res.json?.data?.inserted, 1);

    const row = await get(`SELECT * FROM questions WHERE content = ?`, ['0分判断题示例']);
    assert.ok(row);
    assert.equal(row.score, 0);
    assert.equal(row.type, 'judgment');
  } finally {
    await new Promise<void>((resolve) => server.close(() => resolve()));
  }
});

test('题目类别列表应返回题库数量统计', async () => {
  const { initDatabase, run } = await import('../api/database');
  await initDatabase();

  const { app } = await import('../api/server');
  const server = app.listen(0);

  try {
    const addr = server.address();
    assert.ok(addr && typeof addr === 'object');
    const baseUrl = `http://127.0.0.1:${addr.port}`;

    await run(`DELETE FROM quiz_answers`);
    await run(`DELETE FROM quiz_records`);
    await run(`DELETE FROM questions`);
    await run(`DELETE FROM question_categories`);

    await run(`INSERT INTO question_categories (id, name) VALUES (?, ?)`, [randomUUID(), '空类别']);

    const q1 = randomUUID();
    const q2 = randomUUID();
    const q3 = randomUUID();
    const q4 = randomUUID();
    const q5 = randomUUID();

    await run(
      `INSERT INTO questions (id, content, type, options, answer, score, category)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [q1, '数学题1', 'single', JSON.stringify(['A', 'B']), 'A', 5, '数学'],
    );
    await run(
      `INSERT INTO questions (id, content, type, options, answer, score, category)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [q2, '数学题2', 'single', JSON.stringify(['A', 'B']), 'A', 5, '数学'],
    );
    await run(
      `INSERT INTO questions (id, content, type, options, answer, score, category)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [q3, '英语题1', 'single', JSON.stringify(['A', 'B']), 'A', 5, '英语'],
    );
    await run(
      `INSERT INTO questions (id, content, type, options, answer, score, category)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [q4, '通用题1', 'single', JSON.stringify(['A', 'B']), 'A', 5, '通用'],
    );
    await run(
      `INSERT INTO questions (id, content, type, options, answer, score, category)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [q5, '空类别题(旧数据)', 'single', JSON.stringify(['A', 'B']), 'A', 5, ''],
    );

    const res = await jsonFetch(baseUrl, '/api/question-categories');
    assert.equal(res.status, 200);
    assert.equal(res.json?.success, true);
    assert.equal(Array.isArray(res.json?.data), true);

    const list = res.json?.data as any[];
    const findByName = (name: string) => list.find((c) => c?.name === name);

    assert.equal(findByName('数学')?.questionCount, 2);
    assert.equal(findByName('英语')?.questionCount, 1);
    assert.equal(findByName('通用')?.questionCount, 2);
    assert.equal(findByName('空类别')?.questionCount, 0);
  } finally {
    await new Promise<void>((resolve) => server.close(() => resolve()));
  }
});
