// ============================================================
// AlipayService — 支付宝登录 / 注册业务逻辑
//
// ── 完整流程 ──────────────────────────────────────────────
//   1. Flutter tobias.authCode() 拉起支付宝 App
//      用户确认授权 → 支付宝 App 回传 auth_code
//
//   2. 客户端将 auth_code 发送到 POST /api/v1/auth/alipay
//
//   3. 本服务调用 AlipayProvider.exchangeAuthCode(authCode)
//      → 获得 access_token、user_id
//
//   4. 调用 AlipayProvider.getUserInfo(access_token)
//      → 获得 nick_name、avatar、user_id
//
//   5. 用 user_id 在 social_accounts 表查找已有绑定
//      （支付宝 user_id 全局唯一，等同于微信的 unionid，无需两步查找）
//
//   6a. 老用户: 同步昵称/头像 → 返回 JWT
//   6b. 新用户: 创建 users + social_accounts → 发布 UserRegistered 事件 → 返回 JWT
//
// ── 支付宝 user_id 特性 ───────────────────────────────────
//   支付宝的 user_id 是全局唯一的（2088 开头的16位数字），
//   同一用户在不同应用下 user_id 相同 → 直接用 user_id 作为 openid 查找即可，
//   无需像微信那样区分 openid vs unionid。
// ============================================================

import { Injectable, Logger, Inject } from '@nestjs/common';
import { AlipayProvider } from '../../infrastructure/alipay/alipay.provider';
import { SOCIAL_ACCOUNT_REPOSITORY, ISocialAccountRepository } from '../../domain/repositories/social-account.repository.interface';
import { SocialProvider } from '../../domain/entities/social-account.entity';
import { USER_REPOSITORY, IUserRepository } from '../../domain/repositories/user.repository.interface';
import { TokenService } from './token.service';
import { EventPublisherService } from './event-publisher.service';
import { UserRole, UserStatus } from '../../domain/entities/user.entity';
import { AuthResult } from './auth.service';
import { Password } from '../../domain/value-objects/password.vo';
import * as crypto from 'crypto';

@Injectable()
export class AlipayService {
  private readonly logger = new Logger('AlipayService');

  constructor(
    private readonly alipayProvider: AlipayProvider,
    @Inject(SOCIAL_ACCOUNT_REPOSITORY)
    private readonly socialAccountRepo: ISocialAccountRepository,
    @Inject(USER_REPOSITORY)
    private readonly userRepo: IUserRepository,
    private readonly tokenService: TokenService,
    private readonly eventPublisher: EventPublisherService,
  ) {}

  async loginOrRegister(
    authCode: string,
    referralCode?: string,
    deviceInfo?: string,
    ipAddress?: string,
  ): Promise<AuthResult> {
    // Step 1: auth_code → access_token + user_id
    const tokenResp = await this.alipayProvider.exchangeAuthCode(authCode);
    const { access_token, user_id } = tokenResp;

    // Step 2: 获取支付宝用户信息
    const userInfo = await this.alipayProvider.getUserInfo(access_token);

    const nickname = userInfo.nick_name?.trim() || `alipay_${user_id.slice(-6)}`;
    const avatarUrl = userInfo.avatar || null;
    const rawData = userInfo as unknown as Record<string, unknown>;

    // Step 3: 查找已有绑定（支付宝 user_id 全局唯一，直接用 openid 查找）
    let socialAccount = await this.socialAccountRepo.findByProviderAndOpenid(
      SocialProvider.ALIPAY,
      user_id,
    );

    if (socialAccount) {
      // ── 老用户：同步最新信息 ──
      socialAccount.nickname = nickname;
      socialAccount.avatarUrl = avatarUrl;
      await this.socialAccountRepo.save(socialAccount);

      const user = await this.userRepo.findById(socialAccount.userId);
      if (!user || user.status !== UserStatus.ACTIVE) {
        throw new Error('账号已禁用，请联系客服');
      }

      user.recordLoginSuccess(ipAddress);
      await this.userRepo.save(user);

      const tokens = await this.tokenService.generateTokenPair(user.id, user.role, user.kycLevel);
      await this.tokenService.storeRefreshToken(user.id, tokens.refreshToken, deviceInfo, ipAddress);

      await this.eventPublisher.publishUserLoggedIn({
        userId: user.id,
        ipAddress: ipAddress || null,
        deviceInfo: deviceInfo || null,
        timestamp: new Date().toISOString(),
      });

      this.logger.log(`Alipay login: userId=${user.id} alipayUserId=${user_id}`);
      return { user: this.toUserDto(user), tokens };
    }

    // ── 新用户：自动注册 ──
    const randomPw = await Password.create(crypto.randomBytes(32).toString('hex'));
    const randomPasswordHash = randomPw.value;

    const user = await this.userRepo.create({
      phone: null,
      email: null,
      passwordHash: randomPasswordHash,
      nickname,
      role: UserRole.USER,
      status: UserStatus.ACTIVE,
      kycLevel: 0,
      walletMode: 'standard',
    });

    await this.socialAccountRepo.create({
      userId: user.id,
      provider: SocialProvider.ALIPAY,
      openid: user_id,
      nickname,
      avatarUrl: avatarUrl || undefined,
      rawData,
    });

    const tokens = await this.tokenService.generateTokenPair(user.id, user.role, user.kycLevel);
    await this.tokenService.storeRefreshToken(user.id, tokens.refreshToken, deviceInfo, ipAddress);

    await this.eventPublisher.publishUserRegistered({
      userId: user.id,
      phone: null,
      email: null,
      role: user.role,
      referralCode: referralCode?.toUpperCase() ?? null,
      timestamp: new Date().toISOString(),
    });

    this.logger.log(`Alipay new user registered: userId=${user.id} alipayUserId=${user_id}`);
    return { user: this.toUserDto(user), tokens };
  }

  private toUserDto(user: any) {
    return {
      id: user.id,
      phone: user.phone ?? null,
      email: user.email ?? null,
      nickname: user.nickname ?? null,
      avatarUrl: user.avatarUrl ?? null,
      role: user.role,
      kycLevel: user.kycLevel,
      walletMode: user.walletMode,
    };
  }
}
