// ============================================================
// AppleService — Apple Sign In 登录 / 注册业务逻辑
//
// Apple sub（user identifier）是全局唯一的，直接用作 openid
// 注意: Apple 只在首次授权时返回 email，之后登录不再提供
//       → 首次注册时将 email 写入 users 表；后续登录无需更新
// ============================================================

import { Injectable, Logger, Inject } from '@nestjs/common';
import { AppleProvider } from '../../infrastructure/apple/apple.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 AppleService {
  private readonly logger = new Logger('AppleService');

  constructor(
    private readonly appleProvider: AppleProvider,
    @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(
    identityToken: string,
    /** 客户端传入的 displayName（Apple 首次授权时用户可修改，之后不再提供） */
    displayName?: string,
    referralCode?: string,
    deviceInfo?: string,
    ipAddress?: string,
  ): Promise<AuthResult> {
    // Step 1: 验证 Apple Identity Token
    const appleUser = await this.appleProvider.verifyIdentityToken(identityToken);
    const { sub, email } = appleUser;

    const nickname = displayName?.trim() || `apple_${sub.slice(-6)}`;
    const rawData = appleUser as unknown as Record<string, unknown>;

    // Step 2: 查找已有绑定
    let socialAccount = await this.socialAccountRepo.findByProviderAndOpenid(
      SocialProvider.APPLE,
      sub,
    );

    if (socialAccount) {
      // ── 老用户（Apple 后续登录昵称不更新，因为 Apple 不再提供） ──
      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(`Apple login: userId=${user.id} sub=${sub.slice(0, 6)}...`);
      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: email || null,
      passwordHash: randomPasswordHash,
      nickname,
      role: UserRole.USER,
      status: UserStatus.ACTIVE,
      kycLevel: 0,
      walletMode: 'standard',
    });

    await this.socialAccountRepo.create({
      userId: user.id,
      provider: SocialProvider.APPLE,
      openid: sub,
      nickname,
      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: email || null,
      role: user.role,
      referralCode: referralCode?.toUpperCase() ?? null,
      timestamp: new Date().toISOString(),
    });

    this.logger.log(`Apple new user registered: userId=${user.id} sub=${sub.slice(0, 6)}...`);
    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,
    };
  }
}
