import { BadRequestException } from '@nestjs/common';
import type {
  AiReviewRow,
  AiReviewSection,
  AiReviewSectionType,
} from './entities/ai-review.entity';
import {
  assertKeys,
  COLUMN_KEYS_ALLOWED,
  COLUMN_KEY_RE,
  isPlainRecord,
  MAX_CELL_LENGTH,
  MAX_COLUMNS,
  MAX_COLUMN_KEY,
  MAX_COLUMN_TITLE,
  MAX_ISSUES,
  MAX_ISSUE_LENGTH,
  MAX_ROWS,
  MAX_SECTIONS,
  MAX_SECTION_TITLE,
  MAX_SUMMARY,
  MAX_TITLE,
  normalizeSectionType,
  requireString,
  SCHEMA_KEYS,
  SECTION_ALIASES,
  SECTION_KEYS_ALLOWED,
  SECTION_KEY_RE,
  ValidatedReviewSchema,
} from './ai-review.shared';

export function validateSchema(rawArgs: unknown): ValidatedReviewSchema {
  if (!isPlainRecord(rawArgs)) throw new BadRequestException('导入预览参数必须是对象');
  assertKeys(rawArgs, SCHEMA_KEYS, '导入预览');
  const title = requireString(rawArgs.title, '预览标题', MAX_TITLE);
  const summary = requireString(rawArgs.summary, '预览说明', MAX_SUMMARY, true) || null;
  if (!Array.isArray(rawArgs.sections) || rawArgs.sections.length === 0) {
    throw new BadRequestException('导入预览至少需要一个分表');
  }
  if (rawArgs.sections.length > MAX_SECTIONS) {
    throw new BadRequestException(`分表数量不能超过 ${MAX_SECTIONS}`);
  }
  const seenKeys = new Set<string>();
  const sections = rawArgs.sections.map((item, index) =>
    validateSection(item, index, seenKeys),
  );
  return { title, summary, sections };
}

function validateSection(
  raw: unknown,
  index: number,
  seenKeys: Set<string>,
): AiReviewSection {
  if (!isPlainRecord(raw)) throw new BadRequestException(`第 ${index + 1} 个分表格式无效`);
  assertKeys(raw, SECTION_KEYS_ALLOWED, `第 ${index + 1} 个分表`);
  const key = requireString(raw.key, `第 ${index + 1} 个分表标识`, MAX_COLUMN_KEY);
  if (!SECTION_KEY_RE.test(key)) {
    throw new BadRequestException(
      `分表标识 ${key} 只能包含字母、数字、下划线（≤50）`,
    );
  }
  const type = normalizeSectionType(key, raw.type);
  if (seenKeys.has(key)) throw new BadRequestException(`分表标识重复: ${key}`);
  seenKeys.add(key);
  const title = requireString(raw.title, `分表「${key}」标题`, MAX_SECTION_TITLE);
  if (raw.kind !== 'table') throw new BadRequestException(`分表「${key}」的 kind 只能是 table`);
  const sheet =
    raw.sheet === undefined || raw.sheet === null
      ? undefined
      : requireString(raw.sheet, `分表「${key}」工作表`, MAX_SECTION_TITLE);
  if (!Array.isArray(raw.columns) || raw.columns.length === 0) {
    throw new BadRequestException(`分表「${key}」至少需要一个列`);
  }
  if (raw.columns.length > MAX_COLUMNS) {
    throw new BadRequestException(`分表「${key}」的列数不能超过 ${MAX_COLUMNS}`);
  }
  const seenColumns = new Set<string>();
  const aliases = SECTION_ALIASES[type] ?? {};
  const columns = raw.columns.map((column, columnIndex) => {
    if (!isPlainRecord(column)) {
      throw new BadRequestException(`分表「${key}」第 ${columnIndex + 1} 列格式无效`);
    }
    assertKeys(column, COLUMN_KEYS_ALLOWED, `分表「${key}」第 ${columnIndex + 1} 列`);
    const rawKey = requireString(column.key, `分表「${key}」列名`, MAX_COLUMN_KEY);
    const columnKey = aliases[rawKey] ?? rawKey;
    if (!COLUMN_KEY_RE.test(columnKey)) {
      throw new BadRequestException(`分表「${key}」列名 ${columnKey} 只能包含字母、数字、下划线`);
    }
    if (seenColumns.has(columnKey)) {
      throw new BadRequestException(`分表「${key}」列名重复: ${columnKey}`);
    }
    seenColumns.add(columnKey);
    const columnTitle = requireString(column.title, `分表「${key}」列「${columnKey}」标题`, MAX_COLUMN_TITLE);
    return { key: columnKey, title: columnTitle };
  });
  if (!Array.isArray(raw.rows) || raw.rows.length > MAX_ROWS) {
    throw new BadRequestException(`分表「${key}」的行数不能超过 ${MAX_ROWS}`);
  }
  const rows = raw.rows.map((row, rowIndex) =>
    validateRow(row, type, rowIndex, new Set(seenColumns), aliases),
  );
  let issues: string[] = [];
  if (raw.issues !== undefined) {
    if (!Array.isArray(raw.issues) || raw.issues.length > MAX_ISSUES) {
      throw new BadRequestException(`分表「${key}」的问题数不能超过 ${MAX_ISSUES}`);
    }
    issues = raw.issues.map((issue) =>
      requireString(issue, `分表「${key}」的问题`, MAX_ISSUE_LENGTH),
    );
  }
  return {
    key,
    type,
    title,
    kind: 'table',
    ...(sheet ? { sheet } : {}),
    columns,
    rows,
    issues,
  };
}

function validateRow(
  raw: unknown,
  sectionType: AiReviewSectionType,
  index: number,
  knownColumns: Set<string>,
  aliases: Record<string, string>,
): AiReviewRow {
  if (!isPlainRecord(raw)) {
    throw new BadRequestException(`分表「${sectionType}」第 ${index + 1} 行格式无效`);
  }
  const row: AiReviewRow = {};
  for (const [key, value] of Object.entries(raw)) {
    const canonicalKey = aliases[key] ?? key;
    if (!knownColumns.has(canonicalKey)) continue;
    if (value === null || typeof value === 'boolean') {
      row[canonicalKey] = value;
      continue;
    }
    if (typeof value === 'number') {
      if (!Number.isFinite(value)) {
        throw new BadRequestException(
          `分表「${sectionType}」第 ${index + 1} 行 ${key} 必须是有效数字`,
        );
      }
      row[canonicalKey] = value;
      continue;
    }
    if (typeof value === 'string') {
      if (value.length > MAX_CELL_LENGTH) {
        throw new BadRequestException(
          `分表「${sectionType}」第 ${index + 1} 行 ${key} 长度超过 ${MAX_CELL_LENGTH}`,
        );
      }
      row[canonicalKey] = value;
      continue;
    }
    throw new BadRequestException(
      `分表「${sectionType}」第 ${index + 1} 行 ${key} 类型不支持`,
    );
  }
  return row;
}
