/**
 * 用户档案数据传输对象模块
 * 
 * 功能描述：
 * - 定义用户档案相关的数据传输对象
 * - 提供数据验证和类型约束
 * - 支持位置信息的创建和更新操作
 * - 实现完整的数据传输层抽象
 * 
 * 职责分离：
 * - 数据验证：使用class-validator进行输入验证
 * - 类型定义：TypeScript类型安全保证
 * - 数据转换：支持前端到后端的数据映射
 * - 接口规范：统一的API数据格式
 * 
 * 依赖模块：
 * - class-validator: 数据验证装饰器
 * - class-transformer: 数据转换装饰器
 * 
 * 最近修改：
 * - 2026-01-08: 功能新增 - 创建用户档案DTO，支持位置广播系统 (修改者: moyin)
 * 
 * @author moyin
 * @version 1.0.0
 * @since 2026-01-08
 * @lastModified 2026-01-08
 */

import { IsString, IsNumber, IsOptional, IsNotEmpty, IsObject, IsInt, Min, Max, Length } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

/**
 * 创建用户档案DTO
 * 
 * 职责：
 * - 定义创建用户档案时的必需和可选字段
 * - 提供完整的数据验证规则
 * - 支持位置信息的初始化
 * 
 * 验证规则：
 * - user_id: 必需，正整数
 * - current_map: 必需，非空字符串，长度1-50
 * - pos_x, pos_y: 必需，数字类型
 * - 其他字段: 可选，有相应的格式验证
 */
export class CreateUserProfileDto {
  /**
   * 关联用户ID
   * 
   * 验证规则：
   * - 必需字段，不能为空
   * - 必须是正整数
   * - 用于关联users表的主键
   */
  @ApiProperty({
    description: '关联的用户ID',
    example: 1,
    type: 'integer'
  })
  @IsNotEmpty({ message: '用户ID不能为空' })
  @Type(() => Number)
  user_id: bigint;

  /**
   * 用户简介
   * 
   * 验证规则：
   * - 可选字段
   * - 字符串类型，最大长度500
   * - 支持多语言和特殊字符
   */
  @ApiPropertyOptional({
    description: '用户自我介绍',
    example: '热爱编程的全栈开发者，喜欢探索新技术',
    maxLength: 500
  })
  @IsOptional()
  @IsString({ message: '简介必须是字符串' })
  @Length(0, 500, { message: '简介长度不能超过500个字符' })
  bio?: string;

  /**
   * 简历内容
   * 
   * 验证规则：
   * - 可选字段
   * - 字符串类型，支持长文本
   * - 可以包含结构化信息
   */
  @ApiPropertyOptional({
    description: '详细简历内容',
    example: '5年全栈开发经验，精通React、Node.js、Python等技术栈...'
  })
  @IsOptional()
  @IsString({ message: '简历内容必须是字符串' })
  resume_content?: string;

  /**
   * 标签信息
   * 
   * 验证规则：
   * - 可选字段
   * - 对象类型，支持嵌套结构
   * - 用于存储兴趣、技能等标签
   */
  @ApiPropertyOptional({
    description: '用户标签信息',
    example: {
      interests: ['游戏', '编程', '音乐'],
      skills: ['JavaScript', 'Python', 'React'],
      personality: ['外向', '创新', '团队合作']
    }
  })
  @IsOptional()
  @IsObject({ message: '标签信息必须是对象格式' })
  tags?: Record<string, any>;

  /**
   * 社交链接
   * 
   * 验证规则：
   * - 可选字段
   * - 对象类型，键值对格式
   * - 值必须是字符串（URL格式）
   */
  @ApiPropertyOptional({
    description: '社交媒体链接',
    example: {
      github: 'https://github.com/username',
      twitter: 'https://twitter.com/username',
      linkedin: 'https://linkedin.com/in/username'
    }
  })
  @IsOptional()
  @IsObject({ message: '社交链接必须是对象格式' })
  social_links?: Record<string, string>;

  /**
   * 皮肤ID
   * 
   * 验证规则：
   * - 可选字段
   * - 整数类型，范围1-999999
   * - 关联皮肤资源库
   */
  @ApiPropertyOptional({
    description: '角色皮肤ID',
    example: 1001,
    minimum: 1,
    maximum: 999999
  })
  @IsOptional()
  @IsInt({ message: '皮肤ID必须是整数' })
  @Min(1, { message: '皮肤ID必须大于0' })
  @Max(999999, { message: '皮肤ID不能超过999999' })
  skin_id?: number;

  /**
   * 当前地图
   * 
   * 验证规则：
   * - 必需字段，默认值'plaza'
   * - 字符串类型，长度1-50
   * - 不能为空字符串
   */
  @ApiProperty({
    description: '当前所在地图',
    example: 'plaza',
    default: 'plaza',
    minLength: 1,
    maxLength: 50
  })
  @IsString({ message: '地图名称必须是字符串' })
  @IsNotEmpty({ message: '地图名称不能为空' })
  @Length(1, 50, { message: '地图名称长度必须在1-50个字符之间' })
  current_map: string = 'plaza';

  /**
   * X坐标
   * 
   * 验证规则：
   * - 必需字段，默认值0
   * - 数字类型，支持小数
   * - 坐标范围由具体地图决定
   */
  @ApiProperty({
    description: 'X轴坐标位置',
    example: 100.5,
    default: 0,
    type: 'number'
  })
  @IsNumber({}, { message: 'X坐标必须是数字' })
  @Type(() => Number)
  pos_x: number = 0;

  /**
   * Y坐标
   * 
   * 验证规则：
   * - 必需字段，默认值0
   * - 数字类型，支持小数
   * - 坐标范围由具体地图决定
   */
  @ApiProperty({
    description: 'Y轴坐标位置',
    example: 200.3,
    default: 0,
    type: 'number'
  })
  @IsNumber({}, { message: 'Y坐标必须是数字' })
  @Type(() => Number)
  pos_y: number = 0;

  /**
   * 用户状态
   * 
   * 验证规则：
   * - 可选字段，默认值0（离线）
   * - 整数类型，范围0-255
   * - 0: 离线，1: 在线，2: 忙碌，3: 隐身
   */
  @ApiPropertyOptional({
    description: '用户状态',
    example: 1,
    default: 0,
    minimum: 0,
    maximum: 255,
    enum: [0, 1, 2, 3],
    enumName: 'UserProfileStatus'
  })
  @IsOptional()
  @IsInt({ message: '用户状态必须是整数' })
  @Min(0, { message: '用户状态不能小于0' })
  @Max(255, { message: '用户状态不能大于255' })
  status?: number = 0;
}

/**
 * 更新用户档案DTO
 * 
 * 职责：
 * - 定义更新用户档案时的可选字段
 * - 继承创建DTO的验证规则
 * - 支持部分字段更新
 * 
 * 特点：
 * - 所有字段都是可选的
 * - 保持与创建DTO相同的验证规则
 * - 支持灵活的部分更新操作
 */
export class UpdateUserProfileDto {
  /**
   * 用户简介（可选更新）
   */
  @ApiPropertyOptional({
    description: '用户自我介绍',
    example: '更新后的自我介绍',
    maxLength: 500
  })
  @IsOptional()
  @IsString({ message: '简介必须是字符串' })
  @Length(0, 500, { message: '简介长度不能超过500个字符' })
  bio?: string;

  /**
   * 简历内容（可选更新）
   */
  @ApiPropertyOptional({
    description: '详细简历内容',
    example: '更新后的简历内容'
  })
  @IsOptional()
  @IsString({ message: '简历内容必须是字符串' })
  resume_content?: string;

  /**
   * 标签信息（可选更新）
   */
  @ApiPropertyOptional({
    description: '用户标签信息',
    example: {
      interests: ['新的兴趣'],
      skills: ['新的技能']
    }
  })
  @IsOptional()
  @IsObject({ message: '标签信息必须是对象格式' })
  tags?: Record<string, any>;

  /**
   * 社交链接（可选更新）
   */
  @ApiPropertyOptional({
    description: '社交媒体链接',
    example: {
      github: 'https://github.com/newusername'
    }
  })
  @IsOptional()
  @IsObject({ message: '社交链接必须是对象格式' })
  social_links?: Record<string, string>;

  /**
   * 皮肤ID（可选更新）
   */
  @ApiPropertyOptional({
    description: '角色皮肤ID',
    example: 2001,
    minimum: 1,
    maximum: 999999
  })
  @IsOptional()
  @IsInt({ message: '皮肤ID必须是整数' })
  @Min(1, { message: '皮肤ID必须大于0' })
  @Max(999999, { message: '皮肤ID不能超过999999' })
  skin_id?: number;

  /**
   * 当前地图（可选更新）
   */
  @ApiPropertyOptional({
    description: '当前所在地图',
    example: 'forest',
    minLength: 1,
    maxLength: 50
  })
  @IsOptional()
  @IsString({ message: '地图名称必须是字符串' })
  @IsNotEmpty({ message: '地图名称不能为空' })
  @Length(1, 50, { message: '地图名称长度必须在1-50个字符之间' })
  current_map?: string;

  /**
   * X坐标（可选更新）
   */
  @ApiPropertyOptional({
    description: 'X轴坐标位置',
    example: 150.7,
    type: 'number'
  })
  @IsOptional()
  @IsNumber({}, { message: 'X坐标必须是数字' })
  @Type(() => Number)
  pos_x?: number;

  /**
   * Y坐标（可选更新）
   */
  @ApiPropertyOptional({
    description: 'Y轴坐标位置',
    example: 250.9,
    type: 'number'
  })
  @IsOptional()
  @IsNumber({}, { message: 'Y坐标必须是数字' })
  @Type(() => Number)
  pos_y?: number;

  /**
   * 用户状态（可选更新）
   */
  @ApiPropertyOptional({
    description: '用户状态',
    example: 2,
    minimum: 0,
    maximum: 255,
    enum: [0, 1, 2, 3]
  })
  @IsOptional()
  @IsInt({ message: '用户状态必须是整数' })
  @Min(0, { message: '用户状态不能小于0' })
  @Max(255, { message: '用户状态不能大于255' })
  status?: number;
}

/**
 * 位置更新DTO
 * 
 * 职责：
 * - 专门用于位置广播系统的位置更新
 * - 只包含位置相关的核心字段
 * - 提供高性能的位置数据传输
 * 
 * 使用场景：
 * - WebSocket位置更新消息
 * - 批量位置同步操作
 * - 位置广播系统的核心数据结构
 */
export class UpdatePositionDto {
  /**
   * 当前地图
   */
  @ApiProperty({
    description: '当前所在地图',
    example: 'plaza',
    minLength: 1,
    maxLength: 50
  })
  @IsString({ message: '地图名称必须是字符串' })
  @IsNotEmpty({ message: '地图名称不能为空' })
  @Length(1, 50, { message: '地图名称长度必须在1-50个字符之间' })
  current_map: string;

  /**
   * X坐标
   */
  @ApiProperty({
    description: 'X轴坐标位置',
    example: 100.5,
    type: 'number'
  })
  @IsNumber({}, { message: 'X坐标必须是数字' })
  @Type(() => Number)
  pos_x: number;

  /**
   * Y坐标
   */
  @ApiProperty({
    description: 'Y轴坐标位置',
    example: 200.3,
    type: 'number'
  })
  @IsNumber({}, { message: 'Y坐标必须是数字' })
  @Type(() => Number)
  pos_y: number;
}

/**
 * 用户档案查询DTO
 * 
 * 职责：
 * - 定义查询用户档案时的过滤条件
 * - 支持分页和排序参数
 * - 提供灵活的查询选项
 */
export class QueryUserProfileDto {
  /**
   * 地图过滤
   */
  @ApiPropertyOptional({
    description: '按地图过滤用户',
    example: 'plaza'
  })
  @IsOptional()
  @IsString({ message: '地图名称必须是字符串' })
  current_map?: string;

  /**
   * 状态过滤
   */
  @ApiPropertyOptional({
    description: '按状态过滤用户',
    example: 1,
    enum: [0, 1, 2, 3]
  })
  @IsOptional()
  @IsInt({ message: '状态必须是整数' })
  @Min(0, { message: '状态不能小于0' })
  @Max(255, { message: '状态不能大于255' })
  status?: number;

  /**
   * 分页大小
   */
  @ApiPropertyOptional({
    description: '每页数量',
    example: 20,
    default: 20,
    minimum: 1,
    maximum: 100
  })
  @IsOptional()
  @IsInt({ message: '分页大小必须是整数' })
  @Min(1, { message: '分页大小不能小于1' })
  @Max(100, { message: '分页大小不能超过100' })
  @Type(() => Number)
  limit?: number = 20;

  /**
   * 偏移量
   */
  @ApiPropertyOptional({
    description: '偏移量',
    example: 0,
    default: 0,
    minimum: 0
  })
  @IsOptional()
  @IsInt({ message: '偏移量必须是整数' })
  @Min(0, { message: '偏移量不能小于0' })
  @Type(() => Number)
  offset?: number = 0;
}