/**
 * 身份证解析工具函数
 * 用于从中国居民身份证号中提取性别和出生日期信息
 */

/**
 * 身份证解析结果接口
 */
export interface IdCardParseResult {
  /** 性别: 男/女 */
  gender: '男' | '女' | null;
  /** 出生日期 YYYY-MM-DD 格式 */
  birthDate: string | null;
  /** 是否成功解析 */
  isValid: boolean;
}

/**
 * 解析身份证号，提取性别和出生日期
 * @param idCard 身份证号（支持15位或18位）
 * @returns 解析结果
 */
export function parseIdCard(idCard: string): IdCardParseResult {
  // 清理输入：移除空格和非数字字符（X保留）
  const cleanedId = idCard.replace(/\s/g, '').toUpperCase();

  // 基本验证：必须是15位或18位
  if (!cleanedId) {
    return { gender: null, birthDate: null, isValid: false };
  }

  // 18位身份证解析
  if (cleanedId.length === 18) {
    return parse18DigitIdCard(cleanedId);
  }

  // 15位身份证解析
  if (cleanedId.length === 15) {
    return parse15DigitIdCard(cleanedId);
  }

  // 长度不符合标准
  return { gender: null, birthDate: null, isValid: false };
}

/**
 * 解析18位身份证号
 * 格式: 6位地区码 + 8位出生日期(YYYYMMDD) + 3位顺序码 + 1位校验码
 * 第17位奇数=男，偶数=女
 */
function parse18DigitIdCard(idCard: string): IdCardParseResult {
  // 验证是否全为数字（最后一位可以是X）
  const body = idCard.substring(0, 17);
  const checkBit = idCard[17];

  if (!/^\d{17}$/.test(body) || !/^[\dX]$/.test(checkBit)) {
    return { gender: null, birthDate: null, isValid: false };
  }

  // 提取出生日期: 第7-14位 (YYYYMMDD)
  const birthDateStr = idCard.substring(6, 14);
  const birthDate = formatBirthDate(birthDateStr, 'YYYYMMDD');

  // 如果出生日期无效，整体解析失败
  if (birthDate === null) {
    return { gender: null, birthDate: null, isValid: false };
  }

  // 提取性别: 第17位，奇数=男，偶数=女
  const genderCode = parseInt(idCard[16], 10);
  const gender = genderCode % 2 === 1 ? '男' : '女';

  return { gender, birthDate, isValid: true };
}

/**
 * 解析15位身份证号
 * 格式: 6位地区码 + 6位出生日期(YYMMDD) + 3位顺序码
 * 第15位奇数=男，偶数=女
 */
function parse15DigitIdCard(idCard: string): IdCardParseResult {
  // 验证是否全为数字
  if (!/^\d{15}$/.test(idCard)) {
    return { gender: null, birthDate: null, isValid: false };
  }

  // 提取出生日期: 第7-12位 (YYMMDD)
  // 15位身份证的年份是2位，需要转换为4位（假设19XX年）
  const birthDateStr = idCard.substring(6, 12);
  const birthDate = formatBirthDate(birthDateStr, 'YYMMDD');

  // 如果出生日期无效，整体解析失败
  if (birthDate === null) {
    return { gender: null, birthDate: null, isValid: false };
  }

  // 提取性别: 第15位，奇数=男，偶数=女
  const genderCode = parseInt(idCard[14], 10);
  const gender = genderCode % 2 === 1 ? '男' : '女';

  return { gender, birthDate, isValid: true };
}

/**
 * 格式化出生日期字符串为 YYYY-MM-DD 格式
 * @param dateStr 日期字符串
 * @param format 输入格式: 'YYYYMMDD' 或 'YYMMDD'
 * @returns 格式化后的日期字符串，无效时返回 null
 */
function formatBirthDate(dateStr: string, format: 'YYYYMMDD' | 'YYMMDD'): string | null {
  let year: string;
  let month: string;
  let day: string;

  if (format === 'YYYYMMDD') {
    year = dateStr.substring(0, 4);
    month = dateStr.substring(4, 6);
    day = dateStr.substring(6, 8);
  } else {
    // YYMMDD: 假设19XX年（15位身份证主要是老版）
    const twoDigitYear = dateStr.substring(0, 2);
    year = `19${twoDigitYear}`;
    month = dateStr.substring(2, 4);
    day = dateStr.substring(4, 6);
  }

  // 验证日期的有效性 - 构造实际日期对象进行验证
  const monthNum = parseInt(month, 10);
  const dayNum = parseInt(day, 10);
  const yearNum = parseInt(year, 10);

  // 验证月份范围
  if (monthNum < 1 || monthNum > 12) {
    return null;
  }

  // 验证日期范围（根据月份）
  const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

  // 处理闰年二月
  const isLeapYear = (yearNum % 4 === 0 && yearNum % 100 !== 0) || (yearNum % 400 === 0);
  if (isLeapYear && monthNum === 2) {
    if (dayNum < 1 || dayNum > 29) {
      return null;
    }
  } else {
    if (dayNum < 1 || dayNum > daysInMonth[monthNum - 1]) {
      return null;
    }
  }

  // 验证年份的合理性（1900-当前年份，不大于当前年份）
  const currentYear = new Date().getFullYear();
  if (yearNum < 1900 || yearNum > currentYear) {
    return null;
  }

  return `${year}-${month}-${day}`;
}

/**
 * 验证身份证号格式是否正确
 * @param idCard 身份证号
 * @returns 是否有效
 */
export function isValidIdCardFormat(idCard: string): boolean {
  const cleanedId = idCard.replace(/\s/g, '').toUpperCase();

  if (cleanedId.length === 18) {
    const body = cleanedId.substring(0, 17);
    const checkBit = cleanedId[17];
    return /^\d{17}$/.test(body) && /^[\dX]$/.test(checkBit);
  }

  if (cleanedId.length === 15) {
    return /^\d{15}$/.test(cleanedId);
  }

  return false;
}
