import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
  IsOptional,
  IsInt,
  IsString,
  IsBoolean,
  IsArray,
  IsEnum,
  Min,
  Max,
  IsNotEmpty,
  ValidateNested,
} from 'class-validator';
import { Type, Transform } from 'class-transformer';

// ============================================================================
// Request DTOs
// ============================================================================

export class GetMessagesQueryDto {
  @ApiPropertyOptional({
    description: 'Anchor message ID or special value',
    example: 'newest',
  })
  @IsOptional()
  @IsString()
  anchor?: string;

  @ApiPropertyOptional({
    description: 'Number of messages before anchor',
    default: 50,
  })
  @IsOptional()
  @IsInt()
  @Min(0)
  @Max(1000)
  @Type(() => Number)
  numBefore?: number = 50;

  @ApiPropertyOptional({
    description: 'Number of messages after anchor',
    default: 0,
  })
  @IsOptional()
  @IsInt()
  @Min(0)
  @Max(1000)
  @Type(() => Number)
  numAfter?: number = 0;

  @ApiPropertyOptional({ description: 'Filter by stream name' })
  @IsOptional()
  @IsString()
  stream?: string;

  @ApiPropertyOptional({ description: 'Filter by topic' })
  @IsOptional()
  @IsString()
  topic?: string;

  @ApiPropertyOptional({ description: 'Search term' })
  @IsOptional()
  @IsString()
  search?: string;
}

export class SendStreamMessageDto {
  @ApiProperty({ description: 'Stream name', example: 'general' })
  @IsString()
  @IsNotEmpty()
  stream: string;

  @ApiProperty({ description: 'Topic name', example: 'greetings' })
  @IsString()
  @IsNotEmpty()
  topic: string;

  @ApiProperty({
    description: 'Message content (Markdown supported)',
    example: 'Hello, world!',
  })
  @IsString()
  @IsNotEmpty()
  content: string;
}

export class SendPrivateMessageDto {
  @ApiProperty({
    description: 'User IDs to send the message to',
    example: [123, 456],
  })
  @IsArray()
  @IsInt({ each: true })
  userIds: number[];

  @ApiProperty({
    description: 'Message content (Markdown supported)',
    example: 'Hello!',
  })
  @IsString()
  @IsNotEmpty()
  content: string;
}

export class GetStreamsQueryDto {
  @ApiPropertyOptional({ description: 'Include public streams', default: true })
  @IsOptional()
  @Transform(({ value }) => value === 'true' || value === true)
  @IsBoolean()
  includePublic?: boolean;

  @ApiPropertyOptional({
    description: 'Include subscribed streams only',
    default: true,
  })
  @IsOptional()
  @Transform(({ value }) => value === 'true' || value === true)
  @IsBoolean()
  includeSubscribed?: boolean;
}

export class SubscribeToStreamDto {
  @ApiProperty({ description: 'Stream name', example: 'announcements' })
  @IsString()
  @IsNotEmpty()
  name: string;

  @ApiPropertyOptional({
    description: 'Stream description',
    example: 'Company announcements',
  })
  @IsOptional()
  @IsString()
  description?: string;
}

export class SubscribeRequestDto {
  @ApiProperty({
    description: 'Streams to subscribe to',
    type: [SubscribeToStreamDto],
  })
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => SubscribeToStreamDto)
  subscriptions: SubscribeToStreamDto[];

  @ApiPropertyOptional({
    description: 'Make stream invite-only',
    default: false,
  })
  @IsOptional()
  @IsBoolean()
  inviteOnly?: boolean;
}

export class GetUsersQueryDto {
  @ApiPropertyOptional({
    description: 'Include custom profile fields',
    default: false,
  })
  @IsOptional()
  @Transform(({ value }) => value === 'true' || value === true)
  @IsBoolean()
  includeCustomProfileFields?: boolean;
}

// ============================================================================
// Response DTOs
// ============================================================================

export class MessageResponseDto {
  @ApiProperty()
  id: number;

  @ApiProperty()
  senderId: number;

  @ApiProperty()
  senderEmail: string;

  @ApiProperty()
  senderFullName: string;

  @ApiProperty()
  content: string;

  @ApiProperty()
  type: 'stream' | 'private';

  @ApiPropertyOptional()
  streamId?: number;

  @ApiPropertyOptional()
  streamName?: string;

  @ApiProperty()
  subject: string;

  @ApiProperty()
  timestamp: number;

  @ApiProperty()
  avatarUrl: string;
}

export class SendMessageResponseDto {
  @ApiProperty()
  id: number;

  @ApiProperty()
  result: string;

  @ApiProperty()
  message: string;
}

export class StreamResponseDto {
  @ApiProperty()
  streamId: number;

  @ApiProperty()
  name: string;

  @ApiProperty()
  description: string;

  @ApiProperty()
  inviteOnly: boolean;

  @ApiProperty()
  isWebPublic: boolean;

  @ApiProperty()
  dateCreated: number;
}

export class StreamSubscriptionResponseDto extends StreamResponseDto {
  @ApiProperty()
  color: string;

  @ApiProperty()
  isMuted: boolean;

  @ApiProperty()
  pinToTop: boolean;

  @ApiPropertyOptional()
  emailAddress?: string;
}

export class UserResponseDto {
  @ApiProperty()
  userId: number;

  @ApiProperty()
  email: string;

  @ApiProperty()
  fullName: string;

  @ApiProperty()
  avatarUrl: string;

  @ApiProperty()
  isAdmin: boolean;

  @ApiProperty()
  isBot: boolean;

  @ApiProperty()
  isActive: boolean;

  @ApiProperty()
  timezone: string;

  @ApiProperty()
  dateJoined: string;
}

export class MessagesListResponseDto {
  @ApiProperty({ type: [MessageResponseDto] })
  messages: MessageResponseDto[];

  @ApiProperty()
  foundOldest: boolean;

  @ApiProperty()
  foundNewest: boolean;

  @ApiProperty()
  anchor: number;
}
