// ============================================================
// WechatService — 微信登录 / 注册业务逻辑
//
// 流程 (行业标准方案):
//   1. 客户端通过微信 SDK 获取 code（一次性，5 分钟有效）
//   2. 后端用 code 换取 access_token + openid + unionid
//   3. 用 access_token + openid 获取微信用户信息（昵称、头像）
//   4. 按 unionid（优先）或 openid 查找 social_accounts 表
//      - 已存在 → 老用户，同步最新 nickname/avatar，返回 JWT
//      - 不存在 → 新用户，自动注册（创建 user + social_account）
//   5. 发布 UserRegistered 事件（仅新注册时，携带 referralCode）
//
// unionid 优先策略:
//   微信的 openid 是每个 App 不同的，同一用户在不同 App 下 openid 不同。
//   unionid 是绑定到微信开放平台账号后跨 App 统一的。
//   用 unionid 可避免：用户同时安装 genex-mobile 和 admin-app，
//   被识别为两个不同用户。
//
// 自动生成账号信息:
//   - nickname: 来自微信昵称，若为空则生成 "wx_{openid 前8位}"
//   - passwordHash: 随机生成（用户无法用密码登录，只能微信登录）
//   - walletMode: 默认 'standard'
// ============================================================

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

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

  /**
   * 微信一键登录 / 自动注册
   *
   * @param code        客户端从微信 SDK 获取的 code
   * @param referralCode 推荐人的推荐码（可选，仅新用户注册时使用）
   * @param deviceInfo  设备信息（可选）
   * @param ipAddress   客户端 IP（可选）
   */
  async loginOrRegister(
    code: string,
    referralCode?: string,
    deviceInfo?: string,
    ipAddress?: string,
  ): Promise<AuthResult> {
    // Step 1: code → access_token + openid + unionid
    const tokenResp = await this.wechatProvider.exchangeCodeForToken(code);
    const { access_token, openid, unionid } = tokenResp;

    // Step 2: 获取微信用户信息（昵称、头像）
    const userInfo = await this.wechatProvider.getUserInfo(access_token, openid);

    const nickname = userInfo.nickname?.trim() || `wx_${openid.slice(0, 8)}`;
    const avatarUrl = userInfo.headimgurl || null;
    const rawData = userInfo as unknown as Record<string, unknown>;

    // Step 3: 查找已有 social_account
    let socialAccount = await this.findExistingSocialAccount(openid, unionid);

    if (socialAccount) {
      // ── 老用户：同步最新信息并登录 ──
      socialAccount.nickname = nickname;
      socialAccount.avatarUrl = avatarUrl;
      if (unionid && !socialAccount.unionid) {
        // 补充 unionid（首次绑定开放平台时 unionid 才出现）
        socialAccount.unionid = unionid;
      }
      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(`WeChat login: userId=${user.id} openid=${openid.slice(0, 8)}...`);
      return { user: this.toUserDto(user), tokens };
    }

    // ── 新用户：自动注册 ──
    // 使用 Password VO 生成随机哈希（微信用户无需密码登录）
    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.WECHAT,
      openid,
      unionid: unionid || undefined,
      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(`WeChat new user registered: userId=${user.id} openid=${openid.slice(0, 8)}...`);
    return { user: this.toUserDto(user), tokens };
  }

  /**
   * 查找已有的 social_account
   * 优先用 unionid（跨 App 唯一），回退到 openid
   */
  private async findExistingSocialAccount(openid: string, unionid?: string) {
    if (unionid) {
      const byUnionid = await this.socialAccountRepo.findByProviderAndUnionid(
        SocialProvider.WECHAT,
        unionid,
      );
      if (byUnionid) return byUnionid;
    }
    return this.socialAccountRepo.findByProviderAndOpenid(SocialProvider.WECHAT, openid);
  }

  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,
    };
  }
}
