import { ApiProperty, ApiPropertyOptional, PartialType, OmitType } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
  ArrayMaxSize,
  ArrayMinSize,
  IsArray,
  IsDateString,
  IsIn,
  IsInt,
  IsNotEmpty,
  IsNumber,
  IsOptional,
  IsString,
  IsUUID,
  Max,
  MaxLength,
  Min,
  ValidateNested,
} from 'class-validator';

export class CreatePartidaDto {
  @ApiProperty({ example: '02.01', description: 'Código de la partida, único en el proyecto' })
  @IsString()
  @IsNotEmpty({ message: 'Indicá el código de la partida' })
  @MaxLength(20)
  codigo: string;

  @ApiProperty({ example: 'Estructura' })
  @IsString()
  @IsNotEmpty({ message: 'Indicá el rubro' })
  @MaxLength(80)
  rubro: string;

  @ApiProperty({ example: 'Hormigón armado de losas' })
  @IsString()
  @IsNotEmpty({ message: 'Indicá el nombre de la partida' })
  @MaxLength(150)
  nombre: string;

  @ApiProperty({ example: 350000000, description: 'Monto presupuestado sin IVA, en la moneda del proyecto' })
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0, { message: 'El presupuesto no puede ser negativo' })
  monto_presupuestado: number;

  @ApiPropertyOptional() @IsOptional() @IsUUID() etapa_id?: string | null;
  @ApiPropertyOptional() @IsOptional() @IsInt() @Min(0) orden?: number;
}

export class UpdatePartidaDto extends PartialType(CreatePartidaDto) {
  @ApiPropertyOptional({ example: 40, description: 'Avance físico de la partida, en %' })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0)
  @Max(100, { message: 'El avance no puede pasar del 100 %' })
  pct_avance?: number;
}

export class LotePartidasDto {
  @ApiProperty({ type: [CreatePartidaDto] })
  @IsArray()
  @ArrayMinSize(1)
  @ArrayMaxSize(500)
  @ValidateNested({ each: true })
  @Type(() => CreatePartidaDto)
  partidas: CreatePartidaDto[];
}

export class CreateCertificadoDto {
  @ApiProperty() @IsUUID() partida_id: string;
  @ApiProperty({ description: 'Contratista (proveedor)' }) @IsUUID() proveedor_id: string;
  @ApiProperty({ example: '2026-10-31' }) @IsDateString() fecha: string;

  @ApiProperty({
    example: 45000000,
    description: 'Monto certificado en el período, sin IVA, en la moneda del proyecto',
  })
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0.01, { message: 'El monto certificado tiene que ser mayor a cero' })
  monto_bruto: number;

  @ApiPropertyOptional({ example: 35, description: 'Avance acumulado de la partida según este certificado, en %' })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0)
  @Max(100, { message: 'El avance no puede pasar del 100 %' })
  pct_avance?: number;

  @ApiPropertyOptional({ example: 5, description: 'Vacío = el de la configuración' })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0)
  @Max(50, { message: 'El fondo de reparo no puede pasar del 50 %' })
  pct_fondo_reparo?: number;

  @ApiPropertyOptional({ example: 0, description: 'Otras retenciones pactadas, en %' })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0)
  @Max(50, { message: 'La retención no puede pasar del 50 %' })
  pct_retencion?: number;

  @ApiPropertyOptional() @IsOptional() @IsString() @MaxLength(500) descripcion?: string;
}

export class UpdateCertificadoDto extends PartialType(OmitType(CreateCertificadoDto, ['partida_id'] as const)) {}

export class VincularFacturaDto {
  @ApiPropertyOptional({ description: 'Compra (factura del contratista); vacío = desvincular' })
  @IsOptional()
  @IsUUID()
  compra_cab_id?: string | null;
}

export class AnularCertificadoDto {
  @ApiProperty() @IsString() @IsNotEmpty({ message: 'Indicá el motivo' }) @MaxLength(255) motivo: string;
}

export class DevolverFondoDto {
  @ApiProperty({ example: '2027-06-30' }) @IsDateString() fecha: string;
}

export const ORIGENES_IMPUTABLES = ['COMPRA', 'GASTO', 'MANUAL'] as const;
export type OrigenImputable = (typeof ORIGENES_IMPUTABLES)[number];

export class CreateImputacionDto {
  @ApiProperty() @IsUUID() partida_id: string;

  @ApiProperty({ enum: ORIGENES_IMPUTABLES, description: 'Los certificados se imputan solos al aprobarse' })
  @IsIn(ORIGENES_IMPUTABLES as unknown as string[])
  origen: OrigenImputable;

  @ApiPropertyOptional() @IsOptional() @IsUUID() compra_cab_id?: string;
  @ApiPropertyOptional() @IsOptional() @IsUUID() gasto_cab_id?: string;

  @ApiPropertyOptional({
    example: 1500000,
    description: 'Moneda del proyecto, sin IVA. Vacío = lo que queda sin imputar del comprobante',
  })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0.01, { message: 'El monto tiene que ser mayor a cero' })
  monto?: number;

  @ApiPropertyOptional({ example: '2026-10-15', description: 'Sólo MANUAL; el resto toma la del comprobante' })
  @IsOptional()
  @IsDateString()
  fecha?: string;

  @ApiPropertyOptional() @IsOptional() @IsString() @MaxLength(500) descripcion?: string;
}
