/**
 * 注册业务服务
 *
 * 功能描述：
 * - 处理用户注册相关的业务逻辑和流程控制
 * - 整合核心服务，提供完整的注册功能
 * - 处理业务规则、数据格式化和错误处理
 * - 集成Zulip账号创建和关联
 *
 * 职责分离：
 * - 专注于注册业务流程和规则实现
 * - 调用核心服务完成具体功能
 * - 为控制器层提供注册业务接口
 * - 处理注册相关的邮箱验证和Zulip集成
 *
 * 最近修改：
 * - 2026-01-15: 代码规范优化 - 清理未使用的导入TokenPair，增强userId非空验证 (修改者: moyin)
 * - 2026-01-12: 代码分离 - 从login.service.ts中分离注册相关业务逻辑
 *
 * @author moyin
 * @version 1.0.1
 * @since 2026-01-12
 * @lastModified 2026-01-15
 */

import { Injectable, Logger, Inject } from '@nestjs/common';
import { LoginCoreService, RegisterRequest } from '../../core/login_core/login_core.service';
import { Users } from '../../core/db/users/users.entity';
import { ZulipAccountService } from '../../core/zulip_core/services/zulip_account.service';
import { ApiKeySecurityService } from '../../core/zulip_core/services/api_key_security.service';
import { AccountProfilePayload, AccountProfileService } from './account_profile.service';

// Import the interface types we need
interface IZulipAccountsService {
  findByGameUserId(gameUserId: string, includeGameUser?: boolean): Promise<any>;
  create(createDto: any): Promise<any>;
  deleteByGameUserId(gameUserId: string): Promise<boolean>;
}

// 常量定义
const ERROR_CODES = {
  REGISTER_FAILED: 'REGISTER_FAILED',
  SEND_EMAIL_VERIFICATION_FAILED: 'SEND_EMAIL_VERIFICATION_FAILED',
  EMAIL_VERIFICATION_FAILED: 'EMAIL_VERIFICATION_FAILED',
  RESEND_EMAIL_VERIFICATION_FAILED: 'RESEND_EMAIL_VERIFICATION_FAILED',
  TEST_MODE_ONLY: 'TEST_MODE_ONLY',
  INVALID_VERIFICATION_CODE: 'INVALID_VERIFICATION_CODE',
} as const;

const MESSAGES = {
  REGISTER_SUCCESS: '注册成功',
  EMAIL_VERIFICATION_SUCCESS: '邮箱验证成功',
  CODE_SENT: '验证码已发送，请查收',
  EMAIL_CODE_SENT: '验证码已发送，请查收邮件',
  EMAIL_CODE_RESENT: '验证码已重新发送，请查收邮件',
  VERIFICATION_CODE_ERROR: '验证码错误',
  TEST_MODE_WARNING: '⚠️ 测试模式：验证码已生成但未真实发送。请在控制台查看验证码，或配置邮件服务以启用真实发送。',
} as const;

/**
 * 注册响应数据接口
 */
export interface RegisterResponse {
  /** 用户信息 */
  user: {
    id: string;
    username: string;
    nickname: string;
    email?: string;
    phone?: string;
    avatar_url?: string;
    role: number;
    created_at: Date;
  };
  /** 游戏内账号资料 */
  profile?: AccountProfilePayload['profile'];
  /** 访问令牌 */
  access_token: string;
  /** 刷新令牌 */
  refresh_token: string;
  /** 访问令牌过期时间（秒） */
  expires_in: number;
  /** 令牌类型 */
  token_type: string;
  /** 是否为新用户 */
  is_new_user?: boolean;
  /** 消息 */
  message: string;
}

/**
 * 通用响应接口
 */
export interface ApiResponse<T = any> {
  /** 是否成功 */
  success: boolean;
  /** 响应数据 */
  data?: T;
  /** 消息 */
  message: string;
  /** 错误代码 */
  error_code?: string;
}

@Injectable()
export class RegisterService {
  private readonly logger = new Logger(RegisterService.name);

  constructor(
    private readonly loginCoreService: LoginCoreService,
    private readonly zulipAccountService: ZulipAccountService,
    @Inject('ZulipAccountsService') private readonly zulipAccountsService: IZulipAccountsService,
    private readonly apiKeySecurityService: ApiKeySecurityService,
    private readonly accountProfileService: AccountProfileService,
  ) {}

  /**
   * 用户注册
   *
   * @param registerRequest 注册请求
   * @returns 注册响应
   */
  async register(registerRequest: RegisterRequest): Promise<ApiResponse<RegisterResponse>> {
    const startTime = Date.now();
    const operationId = `register_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;

    try {
      this.logger.log(`开始用户注册流程`, {
        operation: 'register',
        operationId,
        username: registerRequest.username,
        email: registerRequest.email,
        timestamp: new Date().toISOString(),
      });

      // 1. 初始化Zulip管理员客户端
      const zulipUnavailableForLocalDebug = this.isZulipUnavailableForLocalDebug();
      if (!zulipUnavailableForLocalDebug) {
        await this.initializeZulipAdminClient();
      } else {
        this.logger.warn('本地调试模式跳过Zulip管理员客户端初始化', {
          operation: 'register',
          operationId,
        });
      }

      // 2. 调用核心服务进行注册
      const authResult = await this.loginCoreService.register(registerRequest);

      // 3. 创建Zulip账号（使用相同的邮箱和密码）- 异步处理，不影响注册流程
      if (registerRequest.email && registerRequest.password && !zulipUnavailableForLocalDebug) {
        // 异步创建Zulip账号，不阻塞注册流程
        this.createZulipAccountWithRetry(
          authResult.user,
          registerRequest.password,
          operationId
        ).then(success => {
          if (success) {
            this.logger.log(`Zulip账号异步创建成功`, {
              operation: 'register',
              operationId,
              gameUserId: authResult.user.id.toString(),
              email: registerRequest.email,
            });
          }
        }).catch(err => {
          // 错误已在重试方法中记录，这里只是确保Promise不会未处理
          this.logger.warn(`Zulip账号异步创建最终失败`, {
            operation: 'register',
            operationId,
            gameUserId: authResult.user.id.toString(),
            email: registerRequest.email,
          });
        });

        this.logger.log(`Zulip账号创建已提交到后台异步处理`, {
          operation: 'register',
          operationId,
          gameUserId: authResult.user.id.toString(),
          email: registerRequest.email,
        });
      } else {
        this.logger.log(`跳过Zulip账号创建：缺少邮箱或密码`, {
          operation: 'register',
          username: registerRequest.username,
          hasEmail: !!registerRequest.email,
          hasPassword: !!registerRequest.password,
          zulipUnavailableForLocalDebug,
        });
      }

      // 4. 生成JWT令牌对
      const tokenPair = await this.loginCoreService.generateTokenPair(authResult.user);
      const profile = await this.accountProfileService.ensureProfile(authResult.user.id, registerRequest.skin_id);
      await this.accountProfileService.sendWelcomeEmailAfterInitialCharacterCreation(authResult.user, profile);

      // 5. 格式化响应数据
      const response: RegisterResponse = {
        user: this.formatUserInfo(authResult.user),
        profile: (await this.accountProfileService.formatAccountProfileAsync(authResult.user, profile)).profile,
        access_token: tokenPair.access_token,
        refresh_token: tokenPair.refresh_token,
        expires_in: tokenPair.expires_in,
        token_type: tokenPair.token_type,
        is_new_user: true,
        message: MESSAGES.REGISTER_SUCCESS
      };

      const duration = Date.now() - startTime;

      this.logger.log(`用户注册成功`, {
        operation: 'register',
        operationId,
        gameUserId: authResult.user.id.toString(),
        username: authResult.user.username,
        email: authResult.user.email,
        duration,
        timestamp: new Date().toISOString(),
      });

      return {
        success: true,
        data: response,
        message: response.message
      };
    } catch (error) {
      const duration = Date.now() - startTime;
      const err = error as Error;

      this.logger.error(`用户注册失败`, {
        operation: 'register',
        operationId,
        username: registerRequest.username,
        email: registerRequest.email,
        error: err.message,
        duration,
        timestamp: new Date().toISOString(),
      }, err.stack);

      return {
        success: false,
        message: err.message || '注册失败',
        error_code: ERROR_CODES.REGISTER_FAILED
      };
    }
  }

  /**
   * 发送邮箱验证码
   *
   * @param email 邮箱地址
   * @returns 响应结果
   */
  async sendEmailVerification(email: string): Promise<ApiResponse<{ verification_code?: string; is_test_mode?: boolean }>> {
    try {
      this.logger.log(`发送邮箱验证码: ${email}`);

      // 调用核心服务发送验证码
      const result = await this.loginCoreService.sendEmailVerification(email);

      this.logger.log(`邮箱验证码已发送: ${email}`);

      return this.handleTestModeResponse(result, MESSAGES.CODE_SENT, MESSAGES.EMAIL_CODE_SENT);
    } catch (error) {
      this.logger.error(`发送邮箱验证码失败: ${email}`, error instanceof Error ? error.stack : String(error));

      return {
        success: false,
        message: error instanceof Error ? error.message : '发送验证码失败',
        error_code: ERROR_CODES.SEND_EMAIL_VERIFICATION_FAILED
      };
    }
  }

  /**
   * 验证邮箱验证码
   *
   * @param email 邮箱地址
   * @param code 验证码
   * @returns 响应结果
   */
  async verifyEmailCode(email: string, code: string): Promise<ApiResponse> {
    try {
      this.logger.log(`验证邮箱验证码: ${email}`);

      // 调用核心服务验证验证码
      const isValid = await this.loginCoreService.verifyEmailCode(email, code);

      if (isValid) {
        this.logger.log(`邮箱验证成功: ${email}`);
        return {
          success: true,
          message: MESSAGES.EMAIL_VERIFICATION_SUCCESS
        };
      } else {
        return {
          success: false,
          message: MESSAGES.VERIFICATION_CODE_ERROR,
          error_code: ERROR_CODES.INVALID_VERIFICATION_CODE
        };
      }
    } catch (error) {
      this.logger.error(`邮箱验证失败: ${email}`, error instanceof Error ? error.stack : String(error));

      return {
        success: false,
        message: error instanceof Error ? error.message : '邮箱验证失败',
        error_code: ERROR_CODES.EMAIL_VERIFICATION_FAILED
      };
    }
  }

  /**
   * 重新发送邮箱验证码
   *
   * @param email 邮箱地址
   * @returns 响应结果
   */
  async resendEmailVerification(email: string): Promise<ApiResponse<{ verification_code?: string; is_test_mode?: boolean }>> {
    try {
      this.logger.log(`重新发送邮箱验证码: ${email}`);

      // 调用核心服务重新发送验证码
      const result = await this.loginCoreService.resendEmailVerification(email);

      this.logger.log(`邮箱验证码已重新发送: ${email}`);

      return this.handleTestModeResponse(result, MESSAGES.CODE_SENT, MESSAGES.EMAIL_CODE_RESENT);
    } catch (error) {
      this.logger.error(`重新发送邮箱验证码失败: ${email}`, error instanceof Error ? error.stack : String(error));

      return {
        success: false,
        message: error instanceof Error ? error.message : '重新发送验证码失败',
        error_code: ERROR_CODES.RESEND_EMAIL_VERIFICATION_FAILED
      };
    }
  }

  /**
   * 格式化用户信息
   *
   * @param user 用户实体
   * @returns 格式化的用户信息
   */
  private formatUserInfo(user: Users) {
    return {
      id: user.id.toString(), // 将bigint转换为字符串
      username: user.username,
      nickname: user.nickname,
      email: user.email,
      phone: user.phone,
      avatar_url: user.avatar_url,
      role: user.role,
      created_at: user.created_at
    };
  }

  /**
   * 处理测试模式响应
   *
   * @param result 核心服务返回的结果
   * @param successMessage 成功时的消息
   * @param emailMessage 邮件发送成功时的消息
   * @returns 格式化的响应
   * @private
   */
  private handleTestModeResponse(
    result: { code: string; isTestMode: boolean },
    successMessage: string,
    emailMessage?: string
  ): ApiResponse<{ verification_code?: string; is_test_mode?: boolean }> {
    if (result.isTestMode) {
      return {
        success: false,
        data: {
          verification_code: result.code,
          is_test_mode: true
        },
        message: MESSAGES.TEST_MODE_WARNING,
        error_code: ERROR_CODES.TEST_MODE_ONLY
      };
    } else {
      return {
        success: true,
        data: {
          is_test_mode: false
        },
        message: emailMessage || successMessage
      };
    }
  }

  /**
   * 初始化Zulip管理员客户端
   *
   * 功能描述：
   * 使用环境变量中的管理员凭证初始化Zulip客户端
   *
   * 业务逻辑：
   * 1. 从环境变量获取管理员配置
   * 2. 验证配置完整性
   * 3. 初始化ZulipAccountService的管理员客户端
   *
   * @throws Error 当配置缺失或初始化失败时
   * @private
   */
  private async initializeZulipAdminClient(): Promise<void> {
    try {
      // 从环境变量获取管理员配置
      const adminConfig = {
        realm: process.env.ZULIP_SERVER_URL || process.env.ZULIP_REALM || '',
        username: process.env.ZULIP_BOT_EMAIL || process.env.ZULIP_ADMIN_EMAIL || '',
        apiKey: process.env.ZULIP_BOT_API_KEY || process.env.ZULIP_ADMIN_API_KEY || '',
      };

      // 验证配置完整性
      if (!adminConfig.realm || !adminConfig.username || !adminConfig.apiKey) {
        throw new Error('Zulip管理员配置不完整，请检查环境变量');
      }

      // 初始化管理员客户端
      const initialized = await this.zulipAccountService.initializeAdminClient(adminConfig);

      if (!initialized) {
        throw new Error('Zulip管理员客户端初始化失败');
      }

    } catch (error) {
      const err = error as Error;
      this.logger.error('Zulip管理员客户端初始化失败', {
        operation: 'initializeZulipAdminClient',
        error: err.message,
      }, err.stack);
      throw error;
    }
  }

  /**
   * 本地调试时允许没有真实Zulip服务。
   *
   * @private
   */
  private isZulipUnavailableForLocalDebug(): boolean {
    const serverUrl = process.env.ZULIP_SERVER_URL || process.env.ZULIP_REALM || '';
    const apiKey = process.env.ZULIP_BOT_API_KEY || process.env.ZULIP_ADMIN_API_KEY || '';
    const degradedModeEnabled = process.env.ZULIP_DEGRADED_MODE_ENABLED === 'true';
    const hasPlaceholderServer = serverUrl.includes('your-zulip-server.com');
    const hasPlaceholderApiKey = !apiKey || apiKey === 'your_bot_api_key';

    return degradedModeEnabled || hasPlaceholderServer || hasPlaceholderApiKey;
  }

  /**
   * 带重试机制的异步创建Zulip账号
   *
   * 功能描述：
   * 异步创建Zulip账号，失败时自动重试最多3次
   * 所有错误只记录日志，不影响用户注册流程
   *
   * @param gameUser 游戏用户信息
   * @param password 用户密码
   * @param operationId 操作ID（用于日志追踪）
   * @param maxRetries 最大重试次数，默认3次
   * @returns Promise<boolean> 是否创建成功
   * @private
   */
  private async createZulipAccountWithRetry(
    gameUser: Users,
    password: string,
    operationId: string,
    maxRetries: number = 3
  ): Promise<boolean> {
    let lastError: Error | null = null;

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        this.logger.log(`尝试创建Zulip账号 (第${attempt}/${maxRetries}次)`, {
          operation: 'createZulipAccountWithRetry',
          operationId,
          attempt,
          maxRetries,
          gameUserId: gameUser.id.toString(),
          email: gameUser.email,
        });

        await this.createZulipAccountForUser(gameUser, password);

        this.logger.log(`Zulip账号创建成功 (第${attempt}次尝试)`, {
          operation: 'createZulipAccountWithRetry',
          operationId,
          attempt,
          gameUserId: gameUser.id.toString(),
          email: gameUser.email,
        });

        return true;

      } catch (error) {
        lastError = error as Error;

        this.logger.warn(`Zulip账号创建失败 (第${attempt}/${maxRetries}次尝试)`, {
          operation: 'createZulipAccountWithRetry',
          operationId,
          attempt,
          maxRetries,
          gameUserId: gameUser.id.toString(),
          email: gameUser.email,
          error: lastError.message,
        });

        // 如果不是最后一次尝试，等待后重试
        if (attempt < maxRetries) {
          const delayMs = attempt * 1000; // 递增延迟：1秒、2秒、3秒
          this.logger.log(`等待${delayMs}ms后重试`, {
            operation: 'createZulipAccountWithRetry',
            operationId,
            attempt,
            delayMs,
          });
          await this.delay(delayMs);
        }
      }
    }

    // 所有重试都失败
    this.logger.error(`Zulip账号创建最终失败，已尝试${maxRetries}次`, {
      operation: 'createZulipAccountWithRetry',
      operationId,
      maxRetries,
      gameUserId: gameUser.id.toString(),
      email: gameUser.email,
      finalError: lastError?.message,
      note: '用户注册已成功，但Zulip账号创建失败。用户可以正常使用游戏，但无法使用聊天功能。',
    }, lastError?.stack);

    return false;
  }

  /**
   * 延迟工具方法
   *
   * @param ms 延迟毫秒数
   * @returns Promise<void>
   * @private
   */
  private delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * 为用户创建或绑定Zulip账号
   *
   * 功能描述：
   * 为新注册的游戏用户创建对应的Zulip账号或绑定已有账号并建立关联
   *
   * 业务逻辑：
   * 1. 检查是否已存在Zulip账号关联
   * 2. 尝试创建Zulip账号（如果已存在则自动绑定）
   * 3. 获取或生成API Key并存储到Redis
   * 4. 在数据库中创建关联记录
   * 5. 建立内存关联（用于当前会话）
   *
   * @param gameUser 游戏用户信息
   * @param password 用户密码（明文）
   * @throws Error 当Zulip账号创建/绑定失败时
   * @private
   */
  private async createZulipAccountForUser(gameUser: Users, password: string): Promise<void> {
    const startTime = Date.now();

    this.logger.log('开始为用户创建或绑定Zulip账号', {
      operation: 'createZulipAccountForUser',
      gameUserId: gameUser.id.toString(),
      email: gameUser.email,
      nickname: gameUser.nickname,
    });

    try {
      // 1. 检查是否已存在Zulip账号关联
      const existingAccount = await this.zulipAccountsService.findByGameUserId(gameUser.id.toString());
      if (existingAccount) {
        this.logger.warn('用户已存在Zulip账号关联，跳过创建', {
          operation: 'createZulipAccountForUser',
          gameUserId: gameUser.id.toString(),
          existingZulipUserId: existingAccount.zulipUserId,
        });
        return;
      }

      // 2. 尝试创建或绑定Zulip账号
      const createResult = await this.zulipAccountService.createZulipAccount({
        email: gameUser.email,
        fullName: gameUser.nickname,
        password: password,
      });

      if (!createResult.success) {
        throw new Error(createResult.error || 'Zulip账号创建/绑定失败');
      }

      // 验证必须获取到 userId（数据库字段 NOT NULL）
      if (createResult.userId === undefined || createResult.userId === null) {
        throw new Error('Zulip账号创建成功但未能获取用户ID，无法建立关联');
      }

      // 3. 处理API Key
      let finalApiKey = createResult.apiKey;

      // 如果是绑定已有账号但没有API Key，尝试重新获取
      if (createResult.isExistingUser && !finalApiKey) {
        const apiKeyResult = await this.zulipAccountService.generateApiKeyForUser(
          createResult.email!,
          password
        );

        if (apiKeyResult.success) {
          finalApiKey = apiKeyResult.apiKey;
        } else {
          this.logger.warn('无法获取已有Zulip账号的API Key', {
            operation: 'createZulipAccountForUser',
            gameUserId: gameUser.id.toString(),
            zulipEmail: createResult.email,
            error: apiKeyResult.error,
          });
        }
      }

      // 4. 存储API Key到Redis
      if (finalApiKey) {
        await this.apiKeySecurityService.storeApiKey(
          gameUser.id.toString(),
          finalApiKey
        );
      }

      // 5. 在数据库中创建关联记录
      await this.zulipAccountsService.create({
        gameUserId: gameUser.id.toString(),
        zulipUserId: createResult.userId,  // 已在上面验证不为 undefined
        zulipEmail: createResult.email!,
        zulipFullName: gameUser.nickname,
        zulipApiKeyEncrypted: finalApiKey ? 'stored_in_redis' : '',
        status: 'active',
      });

      // 注意：不在注册时建立内存关联，Zulip客户端将在WebSocket连接时创建

      const duration = Date.now() - startTime;

      this.logger.log('Zulip账号创建/绑定和关联成功', {
        operation: 'createZulipAccountForUser',
        gameUserId: gameUser.id.toString(),
        zulipUserId: createResult.userId,
        zulipEmail: createResult.email,
        isExistingUser: createResult.isExistingUser,
        hasApiKey: !!finalApiKey,
        duration,
      });

    } catch (error) {
      const err = error as Error;
      const duration = Date.now() - startTime;

      this.logger.error('为用户创建/绑定Zulip账号失败', {
        operation: 'createZulipAccountForUser',
        gameUserId: gameUser.id.toString(),
        email: gameUser.email,
        error: err.message,
        duration,
      }, err.stack);

      // 清理可能创建的部分数据
      try {
        await this.zulipAccountsService.deleteByGameUserId(gameUser.id.toString());
      } catch (cleanupError) {
        this.logger.warn('清理Zulip账号关联数据失败', {
          operation: 'createZulipAccountForUser',
          gameUserId: gameUser.id.toString(),
          cleanupError: (cleanupError as Error).message,
        });
      }

      throw error;
    }
  }
}
