import { Injectable } from '@nestjs/common';

/**
 * 脱敏规则（规则 §5.5）
 *
 * 基于字段名约定自动选择规则；业务可扩展 registerRule() 自定义。
 *
 * 约定：
 * - phone / mobile / phoneNumber：中间 4 位遮挡
 * - email：@ 前遮挡保留首字符
 * - idCard / idNumber / 身份证号：中间 8 位遮挡
 * - bankAccount / bankCard：仅显示后 4 位
 * - amount / salary / cost：HIDDEN 或 ****（由字段级权限 HIDDEN 接管）
 */

type MaskRule = (value: unknown) => string;

@Injectable()
export class MaskingService {
  private rules: Record<string, MaskRule> = {
    phone: this.maskPhone,
    mobile: this.maskPhone,
    phoneNumber: this.maskPhone,
    phone_number: this.maskPhone,
    email: this.maskEmail,
    idCard: this.maskIdCard,
    idNumber: this.maskIdCard,
    id_card: this.maskIdCard,
    id_number: this.maskIdCard,
    bankAccount: this.maskBankAccount,
    bank_account: this.maskBankAccount,
    bankCard: this.maskBankAccount,
  };

  /**
   * 业务模块可注册自定义脱敏规则
   */
  registerRule(fieldName: string, rule: MaskRule) {
    this.rules[fieldName] = rule;
  }

  mask(fieldName: string, value: any): any {
    if (value == null || value === '') return value;
    const rule = this.rules[fieldName];
    if (rule) return rule.call(this, value);
    // 默认规则：字符串显示前 2 + 后 2 + 中间 ****
    if (typeof value === 'string') {
      if (value.length <= 4) return '****';
      return value.slice(0, 2) + '****' + value.slice(-2);
    }
    return '****';
  }

  private maskPhone(value: string): string {
    if (typeof value !== 'string' || value.length < 7) return '****';
    return value.slice(0, 3) + '****' + value.slice(-4);
  }

  private maskEmail(value: string): string {
    if (typeof value !== 'string') return '****';
    const at = value.indexOf('@');
    if (at <= 0) return '****';
    return value[0] + '***' + value.slice(at);
  }

  private maskIdCard(value: string): string {
    if (typeof value !== 'string' || value.length < 10) return '****';
    return value.slice(0, 3) + '***********' + value.slice(-4);
  }

  private maskBankAccount(value: string): string {
    if (typeof value !== 'string' || value.length < 4) return '****';
    return '**** **** **** ' + value.slice(-4);
  }
}
