import { Type } from 'class-transformer';
import {
  IsArray,
  IsBoolean,
  IsByteLength,
  IsInt,
  IsString,
  MaxLength,
  Min,
  ValidateIf,
  ValidateNested,
  Validate,
  ValidatorConstraint,
  ValidatorConstraintInterface,
  IsNotEmpty,
} from 'class-validator';
import { TransformBoolean } from '../../../shared/decorators/class-transformer/transform-boolean.decorator';
import { TransformNumberArray } from '../../../shared/decorators/class-transformer/transform-number-array.decorator';
import { TransformNumber } from '../../../shared/decorators/class-transformer/transform-number.decorator';
import { IsLexoRank } from '../../../shared/decorators/class-validator/is-lexo-rank.decorator';
import { IsOptional } from '../../../shared/decorators/class-validator/is-optional.decorator';
import { MatchesNamesRegex } from '../../../shared/decorators/class-validator/matches-names-regex.decorator';

@ValidatorConstraint({ name: 'stepByStepsUniqueLexoRank', async: false })
export class StepByStepsUniqueLexoRank implements ValidatorConstraintInterface {
  validate(stepBySteps: UpdateRecipe_StepByStep[]) {
    const lexoRanks = stepBySteps.map((stepByStep) => stepByStep.lexoRank);

    const uniqueLexoRanks = new Set(lexoRanks);

    return [...uniqueLexoRanks].length === lexoRanks.length;
  }

  defaultMessage(): string {
    return "A propriedade 'lexoRank' dos items de 'stepBySteps' não deve se repetir";
  }
}

export class UpdateRecipeParamsDto {
  @TransformNumber()
  @IsInt()
  @Min(1)
  id: number;
}

export class UpdateRecipe_Ingredient {
  @TransformNumber()
  @IsInt()
  @Min(1)
  id: number;

  @ValidateIf((object: UpdateRecipe_Ingredient) => {
    if (!object.delete && object.delete !== true) return true;

    delete object.quantity;

    return false;
  })
  @TransformNumber()
  @IsInt()
  @Min(1)
  quantity: number;

  @ValidateIf((object: UpdateRecipe_Ingredient) => {
    if (!object.quantity && object.delete !== false) return true;

    delete object.delete;

    return false;
  })
  @TransformBoolean()
  @IsBoolean()
  delete: boolean;
}

export class UpdateRecipe_StepByStep {
  @IsString()
  @IsLexoRank()
  lexoRank: string;

  @ValidateIf((object: UpdateRecipe_StepByStep) => {
    if (!object.delete && object.delete !== true) return true;

    delete object.description;

    return false;
  })
  @IsString()
  @IsByteLength(1, 65536)
  description: string;

  @ValidateIf((object: UpdateRecipe_StepByStep) => {
    if (!object.description && object.delete !== false) return true;

    delete object.delete;

    return false;
  })
  @TransformBoolean()
  @IsBoolean()
  delete: boolean;
}

export class UpdateRecipeDto {
  @IsOptional()
  @IsString()
  @IsNotEmpty()
  @MaxLength(50)
  @MatchesNamesRegex()
  name?: string;

  @IsOptional()
  @TransformNumber()
  @IsInt()
  @Min(1)
  servings?: number;

  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => UpdateRecipe_Ingredient)
  ingredients?: UpdateRecipe_Ingredient[];

  @IsOptional()
  @IsArray()
  @Validate(StepByStepsUniqueLexoRank)
  @ValidateNested({ each: true })
  @Type(() => UpdateRecipe_StepByStep)
  stepBySteps?: UpdateRecipe_StepByStep[];

  @IsOptional()
  @TransformNumberArray()
  @IsArray()
  @IsInt({ each: true })
  @Min(1, { each: true })
  tagsIds?: number[];
}
