import { PartialType } from '@nestjs/mapped-types';
import { Transform, Type } from 'class-transformer';
import {
  IsArray,
  IsIn,
  IsInt,
  IsOptional,
  IsString,
  Matches,
  MaxLength,
  Min,
  ValidateNested,
} from 'class-validator';
import { DecimalString } from '../../../common/http/decimal.transform';

const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;

export class TradeAdditionDto {
  @Matches(ISO_DATE)
  date!: string;

  @IsOptional()
  @DecimalString()
  quantity?: string | null;

  @IsOptional()
  @DecimalString()
  price?: string | null;

  @IsOptional()
  @DecimalString()
  margin?: string | null;
}

export class TradePartialDto {
  @Matches(ISO_DATE)
  date!: string;

  @IsOptional()
  @DecimalString()
  quantity?: string | null;

  @IsOptional()
  @DecimalString()
  price?: string | null;

  @IsOptional()
  @DecimalString()
  pnl?: string | null;

  @IsOptional()
  @IsString()
  @MaxLength(2000)
  note?: string;
}

export class CreateTradeDto {
  @Matches(ISO_DATE)
  openDate!: string;

  @IsOptional()
  @Matches(ISO_DATE)
  closeDate?: string | null;

  @Transform(({ value }) => (typeof value === 'string' ? value.trim().toUpperCase() : value))
  @IsString()
  @Matches(/^[A-Z0-9._-]{1,30}$/)
  asset!: string;

  @IsIn(['LONG', 'SHORT'])
  dir!: 'LONG' | 'SHORT';

  @IsIn(['Scalp', 'Daytrade', 'Swing'])
  tradeType!: 'Scalp' | 'Daytrade' | 'Swing';

  @IsIn(['OPEN', 'WIN', 'LOSS', 'BREAKEVEN', 'ORDER'])
  result!: 'OPEN' | 'WIN' | 'LOSS' | 'BREAKEVEN' | 'ORDER';

  @IsOptional()
  @DecimalString()
  entry?: string | null;

  @IsOptional()
  @DecimalString()
  exit?: string | null;

  @IsOptional()
  @DecimalString()
  sl?: string | null;

  @IsOptional()
  @DecimalString()
  tp?: string | null;

  @IsOptional()
  @DecimalString()
  liqPrice?: string | null;

  @IsOptional()
  @DecimalString()
  lev?: string | null;

  @IsOptional()
  @DecimalString()
  capital?: string | null;

  @IsOptional()
  @DecimalString()
  qty?: string | null;

  @IsOptional()
  @DecimalString()
  baseQty?: string | null;

  @IsOptional()
  @DecimalString()
  baseEntry?: string | null;

  @IsOptional()
  @DecimalString()
  baseCapital?: string | null;

  @IsOptional()
  @DecimalString()
  pnl?: string | null;

  @IsOptional()
  @IsString()
  @MaxLength(10_000)
  setup?: string;

  @IsOptional()
  @IsString()
  @MaxLength(10_000)
  emotion?: string;

  @IsOptional()
  @IsString()
  @MaxLength(50_000)
  notes?: string;

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

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

export class UpdateTradeDto extends PartialType(CreateTradeDto) {
  @IsInt()
  @Min(1)
  version!: number;
}
