import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
  IsEmail,
  IsEnum,
  IsInt,
  IsOptional,
  IsString,
  Length,
  Max,
  MaxLength,
  Min,
  MinLength,
} from 'class-validator';

export enum SupportStatusDto {
  OPEN = 'OPEN',
  RESOLVED = 'RESOLVED',
  CLOSED = 'CLOSED',
}

export class CreateConversationDto {
  @ApiProperty({ description: 'Short subject / topic of the request.' })
  @IsString()
  @Length(3, 200)
  subject!: string;

  @ApiProperty({ description: 'The first message body.' })
  @IsString()
  @MinLength(1)
  @MaxLength(4000)
  initialMessage!: string;
}

/**
 * Text is optional across the send DTOs because a message may be nothing but
 * attachments. "Neither text nor files" is rejected in the service rather than
 * here — the validator can't see the multipart file parts.
 */
export class SendMessageDto {
  @ApiPropertyOptional({
    description: 'Message text. Optional only when attachments are present.',
  })
  @IsOptional()
  @IsString()
  @MaxLength(4000)
  text?: string;
}

export class CreateGuestConversationDto {
  @ApiProperty({ description: 'Client-generated anonymous id (localStorage).' })
  @IsString()
  @Length(8, 120)
  guestId!: string;

  @ApiProperty({ description: 'Guest full name.' })
  @IsString()
  @Length(1, 120)
  name!: string;

  @ApiProperty({ description: 'Guest email for follow-up.' })
  @IsEmail()
  email!: string;

  @ApiPropertyOptional({ description: 'Guest phone (optional).' })
  @IsOptional()
  @IsString()
  @MaxLength(40)
  phone?: string;

  @ApiProperty()
  @IsString()
  @Length(3, 200)
  subject!: string;

  @ApiProperty()
  @IsString()
  @MinLength(1)
  @MaxLength(4000)
  initialMessage!: string;
}

export class GuestSendMessageDto {
  @ApiProperty({ description: 'The guest id that owns the conversation.' })
  @IsString()
  @Length(8, 120)
  guestId!: string;

  @ApiPropertyOptional({
    description: 'Message text. Optional only when attachments are present.',
  })
  @IsOptional()
  @IsString()
  @MaxLength(4000)
  text?: string;
}

export class GuestIdBodyDto {
  @ApiProperty()
  @IsString()
  @Length(8, 120)
  guestId!: string;
}

export class DeviceSendMessageDto {
  @ApiProperty({ description: 'Client device id (localStorage).' })
  @IsString()
  @Length(8, 120)
  deviceId!: string;

  @ApiPropertyOptional({
    description: 'Message text. Optional only when attachments are present.',
  })
  @IsOptional()
  @IsString()
  @MaxLength(4000)
  text?: string;
}

export class DeviceIdBodyDto {
  @ApiProperty()
  @IsString()
  @Length(8, 120)
  deviceId!: string;
}

export class UpdateStatusDto {
  @ApiProperty({ enum: SupportStatusDto })
  @IsEnum(SupportStatusDto)
  status!: SupportStatusDto;
}

export class ListConversationsQueryDto {
  @ApiPropertyOptional({ enum: SupportStatusDto })
  @IsOptional()
  @IsEnum(SupportStatusDto)
  status?: SupportStatusDto;

  @ApiPropertyOptional({ description: 'Search subject / passenger name.' })
  @IsOptional()
  @IsString()
  search?: string;

  @ApiPropertyOptional({ minimum: 1, default: 1 })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  page?: number;

  @ApiPropertyOptional({ minimum: 1, maximum: 100, default: 100 })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  @Max(100)
  limit?: number;
}

/** Default page size for a thread — roughly two screens of bubbles. */
export const SUPPORT_MESSAGES_DEFAULT_LIMIT = 30;
export const SUPPORT_MESSAGES_MAX_LIMIT = 100;

export class ListMessagesQueryDto {
  @ApiPropertyOptional({
    description:
      "Opaque cursor from a previous response's `nextCursor`. Returns the page " +
      'of messages immediately OLDER than the cursor. Omit for the newest page.',
  })
  @IsOptional()
  @IsString()
  before?: string;

  @ApiPropertyOptional({
    minimum: 1,
    maximum: SUPPORT_MESSAGES_MAX_LIMIT,
    default: SUPPORT_MESSAGES_DEFAULT_LIMIT,
  })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  @Max(SUPPORT_MESSAGES_MAX_LIMIT)
  limit?: number;
}

/** Query form of {@link ListMessagesQueryDto} for the device-scoped thread. */
export class DeviceThreadQueryDto extends ListMessagesQueryDto {
  @ApiProperty({ description: 'Client device id (localStorage).' })
  @IsString()
  @Length(8, 120)
  deviceId!: string;
}
