import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsEmail, IsNotEmpty, IsOptional, IsString, Length, Matches, MinLength } from 'class-validator';

const EMAIL_OR_PHONE_PATTERN = /^([^\s@]+@[^\s@]+\.[^\s@]+|\+?[1-9]\d{9,14})$/;

export class RegisterDto {
  @ApiPropertyOptional({ description: 'Основная почта пользователя', example: 'user@example.com' })
  @IsOptional()
  @IsEmail({}, { message: 'Укажите корректную почту' })
  email?: string;

  @ApiPropertyOptional({ description: 'Основной телефон пользователя', example: '+79990000000' })
  @IsOptional()
  @Matches(/^\+?[1-9]\d{7,14}$/, { message: 'Укажите корректный номер телефона' })
  phone?: string;

  @ApiPropertyOptional({ description: 'Пароль пользователя. Не требуется для passwordless-регистрации.', minLength: 8 })
  @IsOptional()
  @IsString({ message: 'Пароль должен быть строкой' })
  @MinLength(8, { message: 'Пароль должен содержать минимум 8 символов' })
  password?: string;

  @ApiProperty({ description: 'Имя, которое отображается в профиле', example: 'Иван Петров' })
  @IsString({ message: 'Имя должно быть строкой' })
  @IsNotEmpty({ message: 'Укажите имя профиля' })
  displayName!: string;

  @ApiPropertyOptional({ description: 'Публичный логин пользователя', example: 'ivan' })
  @IsOptional()
  @IsString({ message: 'Логин должен быть строкой' })
  username?: string;
}

export class LoginDto {
  @ApiProperty({ description: 'Почта, телефон или логин', example: 'user@example.com' })
  @IsString({ message: 'Логин должен быть строкой' })
  @IsNotEmpty({ message: 'Укажите логин' })
  login!: string;

  @ApiProperty({ description: 'Пароль пользователя' })
  @IsString({ message: 'Пароль должен быть строкой' })
  @IsNotEmpty({ message: 'Укажите пароль' })
  password!: string;

  @ApiProperty({ description: 'Уникальный отпечаток устройства' })
  @IsString({ message: 'Отпечаток устройства должен быть строкой' })
  @IsNotEmpty({ message: 'Передайте отпечаток устройства' })
  fingerprint!: string;

  @ApiPropertyOptional({ description: 'Название устройства', example: 'Chrome на Windows' })
  @IsOptional()
  @IsString({ message: 'Название устройства должно быть строкой' })
  deviceName?: string;

  @ApiPropertyOptional({ description: 'Тип устройства', example: 'WEB' })
  @IsOptional()
  @IsString({ message: 'Тип устройства должен быть строкой' })
  deviceType?: string;
}

export class IdentifyDto {
  @ApiProperty({ description: 'Почта или телефон пользователя', example: 'user@example.com' })
  @IsString({ message: 'Логин должен быть строкой' })
  @IsNotEmpty({ message: 'Укажите почту или телефон' })
  @Matches(EMAIL_OR_PHONE_PATTERN, { message: 'Укажите корректную почту или телефон в формате +79991234567' })
  login!: string;
}

export class PasswordlessOtpDto {
  @ApiProperty({ description: 'Почта или телефон для входа', example: 'user@example.com' })
  @IsString({ message: 'Получатель должен быть строкой' })
  @IsNotEmpty({ message: 'Укажите почту или телефон' })
  @Matches(EMAIL_OR_PHONE_PATTERN, { message: 'Укажите корректную почту или телефон в формате +79991234567' })
  recipient!: string;

  @ApiPropertyOptional({ description: 'Альтернативный канал доставки кода', enum: ['primary', 'email', 'phone', 'backupEmail', 'backupPhone'] })
  @IsOptional()
  @IsString({ message: 'Канал должен быть строкой' })
  channel?: string;
}

export class PasswordlessVerifyDto {
  @ApiProperty({ description: 'Почта или телефон, на который отправлен код', example: 'user@example.com' })
  @IsString({ message: 'Получатель должен быть строкой' })
  @Matches(EMAIL_OR_PHONE_PATTERN, { message: 'Укажите корректную почту или телефон в формате +79991234567' })
  recipient!: string;

  @ApiProperty({ description: 'OTP-код из 6 цифр', example: '123456' })
  @IsString({ message: 'Код должен быть строкой' })
  @Length(6, 6, { message: 'Код должен содержать 6 цифр' })
  @Matches(/^\d+$/, { message: 'Код должен содержать только цифры' })
  code!: string;

  @ApiProperty({ description: 'Уникальный отпечаток устройства' })
  @IsString({ message: 'Отпечаток устройства должен быть строкой' })
  fingerprint!: string;

  @ApiPropertyOptional({ description: 'Название устройства' })
  @IsOptional()
  @IsString({ message: 'Название устройства должно быть строкой' })
  deviceName?: string;

  @ApiPropertyOptional({ description: 'Тип устройства', example: 'WEB' })
  @IsOptional()
  @IsString({ message: 'Тип устройства должен быть строкой' })
  deviceType?: string;
}

export class PasswordLoginDto {
  @ApiPropertyOptional({ description: 'Почта или телефон пользователя для identifier-first входа' })
  @IsOptional()
  @IsString({ message: 'Логин должен быть строкой' })
  @Matches(EMAIL_OR_PHONE_PATTERN, { message: 'Укажите корректную почту или телефон в формате +79991234567' })
  login?: string;

  @ApiPropertyOptional({ description: 'Временный auth_token после успешной OTP-проверки, если используется legacy challenge flow' })
  @IsOptional()
  @IsString({ message: 'Временный токен должен быть строкой' })
  tempAuthToken?: string;

  @ApiProperty({ description: 'Пароль пользователя' })
  @IsString({ message: 'Пароль должен быть строкой' })
  @IsNotEmpty({ message: 'Укажите пароль' })
  password!: string;

  @ApiProperty({ description: 'Уникальный отпечаток устройства' })
  @IsString({ message: 'Отпечаток устройства должен быть строкой' })
  fingerprint!: string;

  @ApiPropertyOptional({ description: 'Название устройства' })
  @IsOptional()
  @IsString({ message: 'Название устройства должно быть строкой' })
  deviceName?: string;

  @ApiPropertyOptional({ description: 'Тип устройства', example: 'WEB' })
  @IsOptional()
  @IsString({ message: 'Тип устройства должен быть строкой' })
  deviceType?: string;
}

export class VerifyPinDto {
  @ApiProperty({ description: 'ID временно заблокированной сессии' })
  @IsString({ message: 'ID сессии должен быть строкой' })
  sessionId!: string;

  @ApiProperty({ description: 'PIN-код из 4-6 цифр', example: '1234' })
  @IsString({ message: 'PIN-код должен быть строкой' })
  @Length(4, 6, { message: 'PIN-код должен содержать от 4 до 6 символов' })
  @Matches(/^\d+$/, { message: 'PIN-код должен содержать только цифры' })
  pin!: string;
}

export class VerifyTotpLoginDto {
  @ApiProperty({ description: 'Временный токен после первичной аутентификации' })
  @IsString({ message: 'Токен подтверждения должен быть строкой' })
  @IsNotEmpty({ message: 'Передайте токен подтверждения' })
  totpChallengeToken!: string;

  @ApiProperty({ description: '6-значный код из приложения-аутентификатора', example: '123456' })
  @IsString({ message: 'Код должен быть строкой' })
  @Length(6, 6, { message: 'Код должен содержать 6 цифр' })
  @Matches(/^\d+$/, { message: 'Код должен содержать только цифры' })
  code!: string;
}

export class BeginTotpLoginDto {
  @ApiProperty({ description: 'Почта или телефон пользователя', example: 'user@example.com' })
  @IsString({ message: 'Получатель должен быть строкой' })
  @IsNotEmpty({ message: 'Укажите почту или телефон' })
  @Matches(EMAIL_OR_PHONE_PATTERN, { message: 'Укажите корректную почту или телефон в формате +79991234567' })
  recipient!: string;

  @ApiProperty({ description: 'Уникальный отпечаток устройства' })
  @IsString({ message: 'Отпечаток устройства должен быть строкой' })
  fingerprint!: string;

  @ApiPropertyOptional({ description: 'Название устройства' })
  @IsOptional()
  @IsString({ message: 'Название устройства должно быть строкой' })
  deviceName?: string;

  @ApiPropertyOptional({ description: 'Тип устройства', example: 'WEB' })
  @IsOptional()
  @IsString({ message: 'Тип устройства должен быть строкой' })
  deviceType?: string;
}

export class RefreshSessionDto {
  @ApiProperty({ description: 'Refresh token текущей сессии' })
  @IsString({ message: 'Refresh token должен быть строкой' })
  @IsNotEmpty({ message: 'Передайте refresh token' })
  refreshToken!: string;

  @ApiPropertyOptional({ description: 'ID сессии для ускоренной проверки' })
  @IsOptional()
  @IsString({ message: 'ID сессии должен быть строкой' })
  sessionId?: string;
}

export class LdapLoginDto {
  @ApiProperty({ description: 'Логин LDAP (sAMAccountName, uid, mail и т.д.)', example: 'ivan.petrov' })
  @IsString({ message: 'Логин должен быть строкой' })
  @IsNotEmpty({ message: 'Укажите LDAP-логин' })
  username!: string;

  @ApiProperty({ description: 'Пароль LDAP' })
  @IsString({ message: 'Пароль должен быть строкой' })
  @IsNotEmpty({ message: 'Укажите пароль' })
  password!: string;

  @ApiProperty({ description: 'Уникальный отпечаток устройства' })
  @IsString({ message: 'Отпечаток устройства должен быть строкой' })
  fingerprint!: string;

  @ApiPropertyOptional({ description: 'Название устройства' })
  @IsOptional()
  @IsString({ message: 'Название устройства должно быть строкой' })
  deviceName?: string;

  @ApiPropertyOptional({ description: 'Тип устройства', example: 'WEB' })
  @IsOptional()
  @IsString({ message: 'Тип устройства должен быть строкой' })
  deviceType?: string;
}
