import {
  IsString,
  IsUUID,
  IsOptional,
  IsNumber,
  IsArray,
  IsEnum,
  IsDateString,
  ValidateNested,
  MaxLength,
  MinLength,
  Min,
  IsObject,
} from 'class-validator';
import { Type } from 'class-transformer';
import { CfdiType, CfdiRelationType, CfdiVersion } from '../enums/cfdi-type.enum.js';

/**
 * DTO para concepto de CFDI
 */
export class CfdiConceptoDto {
  @IsString()
  @MaxLength(50)
  claveProdServ: string;

  @IsString()
  @IsOptional()
  @MaxLength(100)
  noIdentificacion?: string;

  @IsNumber()
  @Min(0)
  cantidad: number;

  @IsString()
  @MaxLength(20)
  claveUnidad: string;

  @IsString()
  @IsOptional()
  @MaxLength(20)
  unidad?: string;

  @IsString()
  @MaxLength(1000)
  descripcion: string;

  @IsNumber()
  @Min(0)
  valorUnitario: number;

  @IsNumber()
  @Min(0)
  importe: number;

  @IsNumber()
  @IsOptional()
  @Min(0)
  descuento?: number;

  @IsString()
  @IsOptional()
  @MaxLength(5)
  objetoImp?: string;

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

/**
 * DTO para impuesto de concepto
 */
export class CfdiImpuestoConceptoDto {
  @IsString()
  @MaxLength(10)
  impuesto: string;

  @IsString()
  @MaxLength(20)
  tipoFactor: string;

  @IsNumber()
  @Min(0)
  tasaOCuota: number;

  @IsNumber()
  @Min(0)
  importe: number;

  @IsNumber()
  @IsOptional()
  @Min(0)
  base?: number;
}

/**
 * DTO para emisor
 */
export class CfdiEmisorDto {
  @IsString()
  @MinLength(12)
  @MaxLength(13)
  rfc: string;

  @IsString()
  @MaxLength(300)
  nombre: string;

  @IsString()
  @MaxLength(10)
  regimenFiscal: string;

  @IsString()
  @IsOptional()
  @MaxLength(5)
  domicilioFiscal?: string;
}

/**
 * DTO para receptor
 */
export class CfdiReceptorDto {
  @IsString()
  @MinLength(12)
  @MaxLength(13)
  rfc: string;

  @IsString()
  @MaxLength(300)
  nombre: string;

  @IsString()
  @MaxLength(10)
  usoCfdi: string;

  @IsString()
  @IsOptional()
  @MaxLength(10)
  regimenFiscalReceptor?: string;

  @IsString()
  @IsOptional()
  @MaxLength(5)
  domicilioFiscalReceptor?: string;
}

/**
 * DTO principal para timbrar una factura
 */
export class StampInvoiceDto {
  @IsUUID()
  tenantId: string;

  @IsUUID()
  companyId: string;

  @IsUUID()
  @IsOptional()
  invoiceId?: string;

  @IsUUID()
  @IsOptional()
  certificateId?: string;

  @IsEnum(CfdiVersion)
  @IsOptional()
  cfdiVersion?: CfdiVersion;

  @IsEnum(CfdiType)
  cfdiType: CfdiType;

  @IsString()
  @IsOptional()
  @MaxLength(25)
  serie?: string;

  @IsString()
  @IsOptional()
  @MaxLength(40)
  folio?: string;

  @IsDateString()
  @IsOptional()
  fechaEmision?: string;

  @ValidateNested()
  @Type(() => CfdiEmisorDto)
  emisor: CfdiEmisorDto;

  @ValidateNested()
  @Type(() => CfdiReceptorDto)
  receptor: CfdiReceptorDto;

  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => CfdiConceptoDto)
  conceptos: CfdiConceptoDto[];

  @IsNumber()
  @Min(0)
  subtotal: number;

  @IsNumber()
  @IsOptional()
  @Min(0)
  descuento?: number;

  @IsNumber()
  @Min(0)
  total: number;

  @IsString()
  @MaxLength(3)
  moneda: string;

  @IsNumber()
  @IsOptional()
  @Min(0)
  tipoCambio?: number;

  @IsString()
  @MaxLength(10)
  formaPago: string;

  @IsString()
  @MaxLength(10)
  metodoPago: string;

  @IsString()
  @IsOptional()
  @MaxLength(100)
  condicionesPago?: string;

  @IsString()
  @MaxLength(5)
  lugarExpedicion: string;

  @IsEnum(CfdiRelationType)
  @IsOptional()
  tipoRelacion?: CfdiRelationType;

  @IsArray()
  @IsOptional()
  @IsUUID('all', { each: true })
  cfdiRelacionados?: string[];

  @IsObject()
  @IsOptional()
  impuestos?: Record<string, any>;

  @IsObject()
  @IsOptional()
  complementos?: Record<string, any>;

  @IsObject()
  @IsOptional()
  metadata?: Record<string, any>;
}

/**
 * DTO de respuesta de timbrado
 */
export class StampResponseDto {
  success: boolean;
  cfdiInvoiceId: string;
  uuid?: string;
  fechaTimbrado?: Date;
  selloSat?: string;
  noCertificadoSat?: string;
  cadenaOriginal?: string;
  xmlTimbrado?: string;
  qrCodeBase64?: string;
  errorCode?: string;
  errorMessage?: string;
}

/**
 * DTO para consultar estado de un CFDI
 */
export class CheckStatusDto {
  @IsUUID()
  tenantId: string;

  @IsString()
  @MinLength(12)
  @MaxLength(13)
  rfcEmisor: string;

  @IsString()
  @MinLength(12)
  @MaxLength(13)
  rfcReceptor: string;

  @IsNumber()
  @Min(0)
  total: number;

  @IsUUID()
  uuid: string;
}
