import { Transform, Type } from 'class-transformer';
import {
  ArrayMinSize,
  IsArray,
  IsEnum,
  IsNumber,
  IsOptional,
  IsString,
  IsUUID,
  MaxLength,
  Min,
  ValidateNested,
} from 'class-validator';
import { SettlementPaymentMode } from '../../../entities/settlement-payment.entity';
import { SettlementPaymentType } from '../../../common/constants/settlement-payment-type';
import { PayoutExcessTreatment } from '../../../entities/supplier-payout.entity';

/**
 * §12e Pay Supplier — one row from the screen's outstanding grid.
 *
 * Service-layer guarantees:
 *   - amount ≤ settlement.outstanding (+ 0.005 fudge for decimal rounding)
 *   - settlement belongs to a booking whose supplier_id matches the
 *     payload's supplier_id
 *   - settlement.currency_id matches the payload's currency_id (same-
 *     currency policy)
 */
export class SupplierPayoutAllocationDto {
  @IsUUID()
  settlement_id: string;

  @IsNumber()
  @Min(0.01)
  amount: number;
}

/**
 * Body for `POST /settlements/pay-supplier`. One submission of the
 * Pay Supplier screen = one payout event + N child settlement
 * payments under a shared voucher_no (`PAY-YYYY-NNNN`).
 */
export class PaySupplierDto {
  @IsUUID()
  supplier_id: string;

  @IsString()
  @IsOptional()
  @MaxLength(200)
  supplier_name?: string;

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

  /** Defaults to BILL_TO_BILL. ON_ACCOUNT rejects allocations and
   *  parks the whole amount on the supplier's prepayment ledger. */
  @IsEnum(SettlementPaymentType)
  @IsOptional()
  payment_type?: SettlementPaymentType;

  @IsEnum(SettlementPaymentMode)
  mode: SettlementPaymentMode;

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

  /** Optional on every payment mode. When both sides are set they must differ. */
  @Transform(({ value }) => (value === '' || value === null ? undefined : value))
  @IsOptional()
  @IsUUID()
  debit_bank_account_id?: string;

  /** Optional on every payment mode. When both sides are set they must differ. */
  @Transform(({ value }) => (value === '' || value === null ? undefined : value))
  @IsOptional()
  @IsUUID()
  credit_bank_account_id?: string;

  @IsUUID()
  currency_id: string;

  @IsNumber()
  @Min(0.01)
  paid_amount: number;

  /** Prepayment drawn from the supplier's credit ledger. Must be ≤ that
   *  balance in the chosen currency (enforced server-side). Counted
   *  alongside `paid_amount` when capping allocations. */
  @IsNumber()
  @IsOptional()
  @Min(0)
  credit_applied?: number;

  /** Empty array when ops is recording an explicit supplier advance
   *  with no specific invoice yet. Service rejects when allocations
   *  AND excess_amount are both zero. */
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => SupplierPayoutAllocationDto)
  @ArrayMinSize(0)
  allocations: SupplierPayoutAllocationDto[];

  /** Required when paid + credit exceeds the allocated total.
   *  PREPAYMENT parks it on the supplier ledger; ADVANCE keeps it on
   *  the voucher only. */
  @IsEnum(PayoutExcessTreatment)
  @IsOptional()
  excess_treatment?: PayoutExcessTreatment;

  @IsString()
  @IsOptional()
  notes?: string;
}
