import { Buffer } from 'node:buffer';
import { HttpError, type RequestContext } from '../../core/http.js';
import { stringParam } from '../../core/request.js';
import { requireTenantContentEditor } from './auth.js';

type ImportType = 'questions' | 'vocabulary' | 'handbook' | 'scoreline' | 'videos';
type TemplateFormat = 'json' | 'csv';

interface FieldSpec {
  field: string;
  label: string;
  required: boolean;
  aliases: string[];
  description: string;
  example: unknown;
}

interface ImportTemplateSpec {
  importType: ImportType;
  title: string;
  description: string;
  fields: FieldSpec[];
  csvRows: string[][];
  jsonExample: unknown;
}

const IMPORT_TYPES = new Set<ImportType>(['questions', 'vocabulary', 'handbook', 'scoreline', 'videos']);
const FORMATS = new Set<TemplateFormat>(['json', 'csv']);

const questionFields: FieldSpec[] = [
  { field: 'legacyId', label: '旧系统ID/外部ID', required: false, aliases: ['legacy_id', 'externalId', 'external_id', 'id'], description: '用于幂等更新，同一租户内重复导入会更新或跳过。', example: 'tj-english-2026-001' },
  { field: 'type', label: '题型', required: true, aliases: ['题型', 'questionType'], description: '支持 choice、multi、judge、reading、short_answer 等新题型编码。', example: 'choice' },
  { field: 'typeLabel', label: '题型显示名', required: false, aliases: ['type_label', '题型名称'], description: '用于保留旧卷面上的题型名称。', example: '单选题' },
  { field: 'content', label: '题干', required: true, aliases: ['题干', 'stem', 'question'], description: '支持 Markdown、KaTeX、图片 URL 和表格。', example: '多租户 SaaS 最重要的安全边界是什么？' },
  { field: 'options', label: '选项', required: false, aliases: ['选项', 'choices', '选项A/选项B'], description: '客观题必填；CSV 可使用选项A、选项B 等列。', example: ['前端隐藏', '后端权限和 RLS'] },
  { field: 'correctOptionIndices', label: '正确选项索引', required: false, aliases: ['correct_option_indices', '答案', 'answer'], description: '客观题答案，从 0 开始；CSV 也支持 A/B/C/D。', example: [1] },
  { field: 'answerText', label: '文字答案', required: false, aliases: ['answer_text', '主观题答案'], description: '填空、简答、论述等主观题使用。', example: '以后端权限和数据库 RLS 为准。' },
  { field: 'explanation', label: '解析', required: false, aliases: ['解析', 'analysis'], description: '题目解析内容。', example: '前端只做展示，最终权限必须由后端强制。' },
  { field: 'difficulty', label: '难度', required: false, aliases: ['难度'], description: '建议 1-5。', example: 2 },
  { field: 'tags', label: '标签', required: false, aliases: ['标签', 'tag'], description: 'JSON 数组或 CSV 中用 | 分隔。', example: ['安全', '多租户'] },
];

const vocabularyFields: FieldSpec[] = [
  { field: 'unitLegacyId', label: '单元外部ID', required: false, aliases: ['unit_legacy_id', 'unitId'], description: '单词单元幂等键。', example: 'tj-english-core-001' },
  { field: 'unitName', label: '单元名称', required: true, aliases: ['unit', '单元', 'name'], description: '单词所属单元名称。', example: '核心词汇 Unit 1' },
  { field: 'wordLegacyId', label: '单词外部ID', required: false, aliases: ['word_legacy_id', 'legacyId'], description: '单词幂等键。', example: 'word-scale' },
  { field: 'word', label: '单词', required: true, aliases: ['单词'], description: '英文单词或词组。', example: 'scale' },
  { field: 'phonetic', label: '音标', required: false, aliases: ['音标'], description: '音标展示文本。', example: '/skeil/' },
  { field: 'meaning', label: '释义', required: true, aliases: ['释义', '中文'], description: '中文释义。', example: 'n. 规模；等级' },
  { field: 'example', label: '例句', required: false, aliases: ['例句'], description: '英文例句。', example: 'The platform must scale safely.' },
  { field: 'difficulty', label: '难度', required: false, aliases: ['难度'], description: '建议 1-5。', example: 2 },
  { field: 'tags', label: '标签', required: false, aliases: ['标签'], description: 'JSON 数组或 CSV 中用 | 分隔。', example: ['高频', 'SaaS'] },
];

const handbookFields: FieldSpec[] = [
  { field: 'subjectName', label: '手册科目', required: true, aliases: ['subject', '手册', 'bookName'], description: '知识手册顶层名称。', example: '专升本英语知识手册' },
  { field: 'chapterName', label: '章节', required: true, aliases: ['chapter', '章节'], description: '章节名称。', example: '第一章 语法基础' },
  { field: 'sectionName', label: '小节', required: false, aliases: ['section', '小节'], description: '可选小节名称。', example: '名词性从句' },
  { field: 'title', label: '知识点标题', required: true, aliases: ['entryTitle', '标题'], description: '知识点条目标题。', example: 'that 引导的主语从句' },
  { field: 'content', label: '正文', required: true, aliases: ['正文', 'markdown'], description: 'Markdown 正文，允许图片和公式。', example: '主语从句可放在句首，也可用 it 作形式主语。' },
  { field: 'summary', label: '摘要', required: false, aliases: ['摘要'], description: '条目摘要。', example: '主语从句核心用法。' },
  { field: 'tags', label: '标签', required: false, aliases: ['标签'], description: 'JSON 数组或 CSV 中用 | 分隔。', example: ['语法'] },
];

const scorelineFields: FieldSpec[] = [
  { field: 'kind', label: '数据类型', required: true, aliases: ['type', '类型'], description: 'field、school、major、record。', example: 'record' },
  { field: 'legacyId', label: '外部ID', required: false, aliases: ['legacy_id', 'externalId'], description: '幂等键。', example: 'tj-score-2026-school-major' },
  { field: 'regionId', label: '地区ID', required: false, aliases: ['region_id'], description: '可由导入目标地区补齐。', example: '00000000-0000-0000-0000-000000000301' },
  { field: 'schoolName', label: '院校名称', required: false, aliases: ['school', '院校'], description: 'school、major、record 常用。', example: '天津职业技术师范大学' },
  { field: 'majorName', label: '专业名称', required: false, aliases: ['major', '专业'], description: 'major、record 常用。', example: '软件工程' },
  { field: 'year', label: '年份', required: false, aliases: ['年份'], description: 'record 必填。', example: 2026 },
  { field: 'fieldKey', label: '动态字段键', required: false, aliases: ['field_key'], description: 'field 必填，例如 minScore。', example: 'minScore' },
  { field: 'fieldName', label: '动态字段名', required: false, aliases: ['field_name'], description: 'field 展示名称。', example: '最低分' },
  { field: 'fieldValues', label: '分数线字段值', required: false, aliases: ['values', '分数字段'], description: 'record 的动态字段 JSON；CSV 支持额外列。', example: { minScore: 188 } },
];

const videoFields: FieldSpec[] = [
  { field: 'legacyId', label: '视频外部ID', required: false, aliases: ['legacy_id', 'externalId'], description: '视频幂等键。', example: 'video-question-001' },
  { field: 'title', label: '标题', required: true, aliases: ['视频标题', 'name'], description: '视频标题。', example: '多租户隔离题解析' },
  { field: 'videoUrl', label: '视频 URL', required: false, aliases: ['video_url', 'url'], description: '外部视频 URL；商用建议改用 content_assets。', example: 'https://cdn.example.test/video.mp4' },
  { field: 'assetId', label: '资源ID', required: false, aliases: ['asset_id'], description: '对象存储资源台账 ID。', example: '00000000-0000-0000-0000-000000000000' },
  { field: 'accessMode', label: '访问模式', required: false, aliases: ['access_mode'], description: 'free、svip、video_quota。', example: 'video_quota' },
  { field: 'questionId', label: '题目ID', required: false, aliases: ['question_id'], description: '绑定题目 ID。', example: '00000000-0000-0000-0000-000000000401' },
  { field: 'legacyQuestionId', label: '题目外部ID', required: false, aliases: ['legacy_question_id'], description: '按旧题目 ID 绑定。', example: 'tj-english-2026-001' },
  { field: 'videoType', label: '视频类型', required: false, aliases: ['video_type'], description: 'specific、general 等。', example: 'specific' },
];

const SPECS: Record<ImportType, ImportTemplateSpec> = {
  questions: {
    importType: 'questions',
    title: '题目导入模板',
    description: '用于导入刷题题库，后端会校验题型、答案、目标科目/分类/集合和租户隔离。',
    fields: questionFields,
    csvRows: [
      ['legacyId', '题型', '题干', '选项A', '选项B', '选项C', '选项D', '答案', '解析', '难度', '标签'],
      ['tj-english-2026-001', 'choice', '多租户 SaaS 最重要的安全边界是什么？', '前端隐藏菜单', '后端权限和 RLS', '浏览器缓存', '静态页面', 'B', '最终权限以后端和 RLS 为准。', '2', '安全|多租户'],
    ],
    jsonExample: {
      items: [
        {
          legacyId: 'tj-english-2026-001',
          type: 'choice',
          typeLabel: '单选题',
          content: '多租户 SaaS 最重要的安全边界是什么？',
          options: ['前端隐藏菜单', '后端权限和 RLS', '浏览器缓存', '静态页面'],
          correctOptionIndices: [1],
          explanation: '最终权限以后端和 RLS 为准。',
          difficulty: 2,
          tags: ['安全', '多租户'],
        },
      ],
    },
  },
  vocabulary: {
    importType: 'vocabulary',
    title: '单词导入模板',
    description: '用于导入背单词单元和单词，后端会按单元归组并幂等写入。',
    fields: vocabularyFields,
    csvRows: [
      ['unitLegacyId', 'unitName', 'wordLegacyId', 'word', 'phonetic', 'meaning', 'example', 'difficulty', 'tags'],
      ['tj-english-core-001', '核心词汇 Unit 1', 'word-scale', 'scale', '/skeil/', 'n. 规模；等级', 'The platform must scale safely.', '2', '高频|SaaS'],
    ],
    jsonExample: {
      units: [
        {
          legacyId: 'tj-english-core-001',
          name: '核心词汇 Unit 1',
          words: [
            {
              legacyId: 'word-scale',
              word: 'scale',
              phonetic: '/skeil/',
              meaning: 'n. 规模；等级',
              example: 'The platform must scale safely.',
              difficulty: 2,
            },
          ],
        },
      ],
    },
  },
  handbook: {
    importType: 'handbook',
    title: '知识手册导入模板',
    description: '用于导入知识手册科目、章节、小节和知识点。',
    fields: handbookFields,
    csvRows: [
      ['subjectName', 'chapterName', 'sectionName', 'title', 'summary', 'content', 'tags'],
      ['专升本英语知识手册', '第一章 语法基础', '名词性从句', 'that 引导的主语从句', '主语从句核心用法。', '主语从句可放在句首，也可用 it 作形式主语。', '语法'],
    ],
    jsonExample: {
      subjects: [
        {
          name: '专升本英语知识手册',
          chapters: [
            {
              name: '第一章 语法基础',
              sections: [
                {
                  name: '名词性从句',
                  entries: [
                    {
                      title: 'that 引导的主语从句',
                      summary: '主语从句核心用法。',
                      content: '主语从句可放在句首，也可用 it 作形式主语。',
                      tags: ['语法'],
                    },
                  ],
                },
              ],
            },
          ],
        },
      ],
    },
  },
  scoreline: {
    importType: 'scoreline',
    title: '分数线导入模板',
    description: '用于导入动态字段、院校、专业和年份分数线记录。',
    fields: scorelineFields,
    csvRows: [
      ['kind', 'legacyId', 'schoolName', 'majorName', 'year', 'fieldKey', 'fieldName', 'minScore'],
      ['field', 'score-field-min', '', '', '', 'minScore', '最低分', ''],
      ['school', 'score-school-001', '天津职业技术师范大学', '', '', '', '', ''],
      ['major', 'score-major-001', '天津职业技术师范大学', '软件工程', '', '', '', ''],
      ['record', 'score-record-2026', '天津职业技术师范大学', '软件工程', '2026', '', '', '188'],
    ],
    jsonExample: {
      fields: [{ legacyId: 'score-field-min', fieldKey: 'minScore', fieldName: '最低分', fieldType: 'number', isTrend: true }],
      schools: [{ legacyId: 'score-school-001', name: '天津职业技术师范大学' }],
      majors: [{ legacyId: 'score-major-001', schoolLegacyId: 'score-school-001', name: '软件工程' }],
      records: [{ legacyId: 'score-record-2026', schoolLegacyId: 'score-school-001', majorLegacyId: 'score-major-001', year: 2026, fieldValues: { minScore: 188 } }],
    },
  },
  videos: {
    importType: 'videos',
    title: '视频解析导入模板',
    description: '用于导入视频解析元数据并绑定到题目。',
    fields: videoFields,
    csvRows: [
      ['legacyId', 'title', 'videoUrl', 'accessMode', 'legacyQuestionId', 'videoType'],
      ['video-question-001', '多租户隔离题解析', 'https://cdn.example.test/video.mp4', 'video_quota', 'tj-english-2026-001', 'specific'],
    ],
    jsonExample: {
      videos: [
        {
          legacyId: 'video-question-001',
          title: '多租户隔离题解析',
          videoUrl: 'https://cdn.example.test/video.mp4',
          accessMode: 'video_quota',
          bindings: [{ legacyQuestionId: 'tj-english-2026-001', videoType: 'specific' }],
        },
      ],
    },
  },
};

function importTypeFromQuery(value: string): ImportType {
  if (!IMPORT_TYPES.has(value as ImportType)) {
    throw new HttpError(400, 'Unsupported importType', 'INVALID_IMPORT_TYPE');
  }
  return value as ImportType;
}

function formatFromQuery(value: string): TemplateFormat {
  const format = value || 'json';
  if (!FORMATS.has(format as TemplateFormat)) {
    throw new HttpError(400, 'Unsupported template format', 'INVALID_TEMPLATE_FORMAT');
  }
  return format as TemplateFormat;
}

function csvEscape(value: unknown) {
  const text = String(value ?? '');
  if (!/[",\r\n]/.test(text)) return text;
  return `"${text.replaceAll('"', '""')}"`;
}

function toCsv(rows: string[][]) {
  return `${rows.map(row => row.map(csvEscape).join(',')).join('\n')}\n`;
}

function contentFor(spec: ImportTemplateSpec, format: TemplateFormat) {
  if (format === 'csv') return toCsv(spec.csvRows);
  return `${JSON.stringify(spec.jsonExample, null, 2)}\n`;
}

export async function importFieldMappingRoute(ctx: RequestContext) {
  await requireTenantContentEditor(ctx);
  const importType = importTypeFromQuery(stringParam(ctx, 'importType'));
  const spec = SPECS[importType];
  return {
    item: {
      importType,
      title: spec.title,
      description: spec.description,
      fields: spec.fields,
      requiredFields: spec.fields.filter(field => field.required).map(field => field.field),
    },
  };
}

export async function importTemplateRoute(ctx: RequestContext) {
  await requireTenantContentEditor(ctx);
  const importType = importTypeFromQuery(stringParam(ctx, 'importType'));
  const format = formatFromQuery(stringParam(ctx, 'format'));
  const spec = SPECS[importType];
  const content = contentFor(spec, format);
  const extension = format === 'csv' ? 'csv' : 'json';
  const mimeType = format === 'csv' ? 'text/csv; charset=utf-8' : 'application/json; charset=utf-8';

  return {
    item: {
      importType,
      format,
      fileName: `${importType}-import-template.${extension}`,
      mimeType,
      contentBase64: Buffer.from(content, 'utf8').toString('base64'),
      contentPreview: content,
      fields: spec.fields,
    },
  };
}
