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

export type CompraDescuentoTipo = 'por_item' | 'global_pct' | 'global_monto';
export type CompraItemDescuentoTipo = 'porcentaje' | 'monto';

export class CompraCabeceraDto {
  @ApiProperty({ description: 'ID del proveedor' })
  @IsUUID()
  @IsNotEmpty()
  proveedor_id: string;

  @ApiProperty({
    description:
      'Depósito asociado a la factura. Ingresa stock aquí solo cuando la empresa afecta inventario en compra directa; si usa Recepciones queda como referencia',
  })
  @IsUUID()
  @IsNotEmpty()
  deposito_id: string;

  @ApiPropertyOptional({ description: 'ID de sucursal' })
  @IsOptional()
  @IsUUID()
  sucursal_id?: string;

  @ApiPropertyOptional({ description: 'ID de moneda' })
  @IsOptional()
  @IsUUID()
  moneda_id?: string;

  @ApiPropertyOptional({
    description: 'Cotización de la moneda respecto a la moneda base (1 para moneda local)',
    default: 1,
  })
  @IsOptional()
  @IsNumber()
  @Min(0)
  cotizacion?: number;

  @ApiPropertyOptional({ description: 'ID de condición de operación (contado/crédito)' })
  @IsOptional()
  @IsUUID()
  condicion_operacion_id?: string;

  @ApiPropertyOptional({ description: 'ID de orden de compra vinculada' })
  @IsOptional()
  @IsUUID()
  orden_compra_id?: string;

  @ApiPropertyOptional({ description: 'ID de requisición vinculada' })
  @IsOptional()
  @IsUUID()
  requisicion_id?: string;

  @ApiPropertyOptional({ description: 'Timbrado del proveedor' })
  @IsOptional()
  @IsString()
  timbrado_proveedor?: string;

  @ApiPropertyOptional({ description: 'Establecimiento de factura proveedor' })
  @IsOptional()
  @IsString()
  establecimiento?: string;

  @ApiPropertyOptional({ description: 'Punto de expedición de factura proveedor' })
  @IsOptional()
  @IsString()
  punto_expedicion?: string;

  @ApiPropertyOptional({ description: 'Número de factura del proveedor' })
  @IsOptional()
  @IsString()
  numero_factura?: string;

  @ApiPropertyOptional({
    description:
      'Comprobante preimpreso (talonario físico). Si es false, el documento es electrónico y ' +
      'ya está declarado en SIFEN/Marangatu, por lo que no se incluye en el Libro IVA Compras.',
    default: true,
  })
  @IsOptional()
  @IsBoolean()
  es_preimpreso?: boolean;

  @ApiPropertyOptional({
    description:
      'Embarque de importación al que pertenece esta factura. Cuando viene, la compra es la ' +
      'factura de mercadería del proveedor del exterior: no va al Libro IVA (no es comprobante ' +
      'paraguayo) y alimenta el componente de costo del embarque.',
  })
  @IsOptional()
  @IsUUID()
  embarque_id?: string;

  @ApiPropertyOptional({
    description: 'Concepto de costo del embarque. Por defecto FOB, que es la mercadería en origen.',
  })
  @IsOptional()
  @IsUUID()
  concepto_costo_id?: string;

  @ApiPropertyOptional({
    description:
      'Componente de costo ya cargado a mano que esta factura viene a respaldar. En vez de crear ' +
      'otro se convierte ese, porque duplicarlo inflaría el costeo del embarque.',
  })
  @IsOptional()
  @IsUUID()
  convertir_componente_id?: string;

  @ApiPropertyOptional({ description: 'Fecha de emisión' })
  @IsOptional()
  @IsDateString()
  fecha_emision?: string;

  @ApiPropertyOptional({ description: 'Fecha vencimiento timbrado' })
  @IsOptional()
  @IsDateString()
  fecha_vencimiento_timbrado?: string;

  @ApiPropertyOptional({ description: 'Plazo de crédito en días' })
  @IsOptional()
  @IsNumber()
  @Min(0)
  plazo_credito?: number;

  @ApiPropertyOptional({ description: 'Observaciones' })
  @IsOptional()
  @IsString()
  observaciones?: string;

  @ApiPropertyOptional({
    description: 'Tipo de descuento a aplicar sobre la compra',
    enum: ['por_item', 'global_pct', 'global_monto'],
    default: 'por_item',
  })
  @IsOptional()
  @IsIn(['por_item', 'global_pct', 'global_monto'])
  descuento_tipo?: CompraDescuentoTipo;

  @ApiPropertyOptional({
    description: 'Porcentaje de descuento global (solo si descuento_tipo=global_pct)',
    default: 0,
  })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 6 })
  @Min(0)
  @Max(100)
  descuento_global_pct?: number;

  @ApiPropertyOptional({
    description: 'Monto de descuento global (solo si descuento_tipo=global_monto)',
    default: 0,
  })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0)
  descuento_global_monto?: number;
}

export class CompraItemDto {
  @ApiPropertyOptional({ description: 'ID del detalle de orden de compra vinculado (matching 3 vías)' })
  @IsOptional()
  @IsUUID()
  orden_compra_det_id?: string;

  @ApiPropertyOptional({ description: 'ID del detalle de requisición vinculado' })
  @IsOptional()
  @IsUUID()
  requisicion_det_id?: string;

  @ApiPropertyOptional({ description: 'ID de producto (si aplica a inventario)' })
  @IsOptional()
  @IsUUID()
  producto_id?: string;

  @ApiPropertyOptional({ description: 'Código producto manual' })
  @IsOptional()
  @IsString()
  codigo_producto?: string;

  @ApiProperty({ description: 'Descripción del ítem' })
  @IsString()
  @IsNotEmpty()
  descripcion: string;

  @ApiProperty({ description: 'Cantidad' })
  @IsNumber({ maxDecimalPlaces: 4 })
  @Min(0.0001)
  cantidad: number;

  @ApiProperty({ description: 'Precio unitario' })
  @IsNumber({ maxDecimalPlaces: 4 })
  @Min(0)
  precio_unitario: number;

  @ApiPropertyOptional({ description: 'Porcentaje de IVA (0, 5, 10)', default: 10 })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0)
  porcentaje_iva?: number;

  @ApiPropertyOptional({
    description: 'Tipo de descuento del ítem',
    enum: ['porcentaje', 'monto'],
    default: 'porcentaje',
  })
  @IsOptional()
  @IsIn(['porcentaje', 'monto'])
  descuento_tipo?: CompraItemDescuentoTipo;

  @ApiPropertyOptional({ description: 'Porcentaje de descuento del ítem', default: 0 })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 6 })
  @Min(0)
  @Max(100)
  descuento_pct?: number;

  @ApiPropertyOptional({
    description: 'Monto de descuento del ítem (calculado si se envía descuento_pct)',
    default: 0,
  })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0)
  descuento_monto?: number;

  @ApiPropertyOptional({
    description: 'Compatibilidad legacy: alias de descuento_pct',
    default: 0,
  })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 6 })
  @Min(0)
  @Max(100)
  descuento_porcentaje?: number;

  @ApiPropertyOptional({ description: 'Si impacta stock', default: true })
  @IsOptional()
  @IsBoolean()
  afecta_stock?: boolean;

  @ApiPropertyOptional({ description: 'Número de lote (si se omite, se genera automáticamente)' })
  @IsOptional()
  @IsString()
  numero_lote?: string;

  @ApiPropertyOptional({ description: 'Compatibilidad legacy: alias de numero_lote' })
  @IsOptional()
  @IsString()
  lote?: string;

  @ApiPropertyOptional({ description: 'Fecha de fabricación del lote' })
  @IsOptional()
  @IsDateString()
  fecha_fabricacion?: string;

  @ApiPropertyOptional({ description: 'Fecha de vencimiento de lote' })
  @IsOptional()
  @IsDateString()
  fecha_vencimiento?: string;
}

export class CompraPagoDto {
  @ApiProperty({ description: 'ID del medio de pago' })
  @IsUUID()
  @IsNotEmpty()
  medio_pago_id: string;

  @ApiPropertyOptional({ description: 'ID de moneda del pago' })
  @IsOptional()
  @IsUUID()
  moneda_id?: string;

  @ApiProperty({ description: 'Monto del pago' })
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0)
  monto: number;

  @ApiPropertyOptional({ description: 'Monto en moneda original' })
  @IsOptional()
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0)
  monto_moneda?: number;

  @ApiPropertyOptional({ description: 'Referencia del pago' })
  @IsOptional()
  @IsString()
  referencia?: string;
}

export class CompraCuotaDto {
  @ApiPropertyOptional({ description: 'Nro de cuota' })
  @IsOptional()
  @IsNumber()
  @Min(1)
  numero_cuota?: number;

  @ApiProperty({ description: 'Fecha de vencimiento de la cuota' })
  @IsDateString()
  fecha_vencimiento: string;

  @ApiProperty({ description: 'Monto de la cuota' })
  @IsNumber({ maxDecimalPlaces: 2 })
  @Min(0.01)
  monto: number;

  @ApiPropertyOptional({ description: 'Observaciones de cuota' })
  @IsOptional()
  @IsString()
  observaciones?: string;
}

export class CreateCompraDto {
  @ApiProperty({ type: CompraCabeceraDto })
  @ValidateNested()
  @Type(() => CompraCabeceraDto)
  cabecera: CompraCabeceraDto;

  @ApiProperty({ type: [CompraItemDto] })
  @IsArray()
  @ArrayMinSize(1)
  @ValidateNested({ each: true })
  @Type(() => CompraItemDto)
  items: CompraItemDto[];

  @ApiPropertyOptional({ type: [CompraPagoDto] })
  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => CompraPagoDto)
  pagos?: CompraPagoDto[];

  @ApiPropertyOptional({ type: [CompraCuotaDto] })
  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => CompraCuotaDto)
  cuotas?: CompraCuotaDto[];
}
