import { Injectable, Inject, BadRequestException, NotFoundException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
  AccountSequence,
  USER_REPOSITORY,
  UserRepository,
  UserKycVerifiedEvent,
} from '@/domain';
import { OutboxService } from './outbox.service';

export interface SubmitKycDto {
  accountSequence: string;
  realName: string;
  idCardNo: string;
  idCardFront: string;  // 文件路径或 base64
  idCardBack: string;
}

export interface ReviewKycDto {
  accountSequence: string;
  approved: boolean;
  rejectReason?: string;
}

export interface KycStatusResult {
  status: string;
  realName?: string;
  idCardNo?: string;  // 脱敏后的
  submittedAt?: Date;
  verifiedAt?: Date;
  rejectReason?: string;
}

@Injectable()
export class KycService {
  constructor(
    @Inject(USER_REPOSITORY)
    private readonly userRepository: UserRepository,
    private readonly configService: ConfigService,
    private readonly outboxService: OutboxService,
  ) {}

  /**
   * 提交 KYC 资料
   */
  async submitKyc(dto: SubmitKycDto): Promise<void> {
    const user = await this.userRepository.findByAccountSequence(
      AccountSequence.create(dto.accountSequence),
    );

    if (!user) {
      throw new NotFoundException('用户不存在');
    }

    // 验证身份证号格式
    if (!this.isValidIdCard(dto.idCardNo)) {
      throw new BadRequestException('身份证号格式无效');
    }

    // 验证姓名格式
    if (!this.isValidRealName(dto.realName)) {
      throw new BadRequestException('姓名格式无效');
    }

    // 保存 KYC 资料
    user.submitKyc(dto.realName, dto.idCardNo, dto.idCardFront, dto.idCardBack);
    await this.userRepository.save(user);
  }

  /**
   * 审核 KYC（管理员）
   */
  async reviewKyc(dto: ReviewKycDto): Promise<void> {
    const user = await this.userRepository.findByAccountSequence(
      AccountSequence.create(dto.accountSequence),
    );

    if (!user) {
      throw new NotFoundException('用户不存在');
    }

    if (dto.approved) {
      user.approveKyc();

      // 发布 KYC 认证通过事件
      await this.outboxService.publish(
        new UserKycVerifiedEvent(
          user.accountSequence.value,
          user.realName!,
          new Date(),
        ),
      );
    } else {
      if (!dto.rejectReason) {
        throw new BadRequestException('拒绝原因不能为空');
      }
      user.rejectKyc(dto.rejectReason);
    }

    await this.userRepository.save(user);
  }

  /**
   * 获取 KYC 状态
   */
  async getKycStatus(accountSequence: string): Promise<KycStatusResult> {
    const user = await this.userRepository.findByAccountSequence(
      AccountSequence.create(accountSequence),
    );

    if (!user) {
      throw new NotFoundException('用户不存在');
    }

    return {
      status: user.kycStatus,
      realName: user.realName ? this.maskName(user.realName) : undefined,
      idCardNo: user.idCardNo ? this.maskIdCard(user.idCardNo) : undefined,
      submittedAt: user.kycSubmittedAt,
      verifiedAt: user.kycVerifiedAt,
      rejectReason: user.kycRejectReason,
    };
  }

  /**
   * 验证身份证号格式（18位）
   */
  private isValidIdCard(idCard: string): boolean {
    const pattern = /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;
    if (!pattern.test(idCard)) {
      return false;
    }

    // 校验码验证
    const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
    const checkCodes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
    let sum = 0;
    for (let i = 0; i < 17; i++) {
      sum += parseInt(idCard[i]) * weights[i];
    }
    const checkCode = checkCodes[sum % 11];
    return idCard[17].toUpperCase() === checkCode;
  }

  /**
   * 验证姓名格式
   */
  private isValidRealName(name: string): boolean {
    // 中文姓名 2-20 个字符
    const pattern = /^[\u4e00-\u9fa5·]{2,20}$/;
    return pattern.test(name);
  }

  /**
   * 脱敏姓名（保留第一个字）
   */
  private maskName(name: string): string {
    if (name.length <= 1) return name;
    return name[0] + '*'.repeat(name.length - 1);
  }

  /**
   * 脱敏身份证号（保留前4后4）
   */
  private maskIdCard(idCard: string): string {
    if (idCard.length !== 18) return idCard;
    return idCard.slice(0, 4) + '*'.repeat(10) + idCard.slice(-4);
  }
}
