import { Transform, Type } from 'class-transformer';
import {
  IsArray,
  IsEnum,
  IsIn,
  IsNotEmpty,
  IsNumber,
  IsOptional,
  IsString,
  IsUUID,
  MaxLength,
  Min,
  ValidateIf,
  ValidateNested,
} from 'class-validator';
import { SettlementPaymentMode } from '../../../entities/settlement-payment.entity';
import { CollectionPartyType } from '../../../entities/payment-collection.entity';
import { PaymentAllocationDto } from './collect-payment.dto';

/**
 * POST /settlements/collect-for-md — stamp cash on a booking (Pending).
 * Optional transport_item_id scopes to one route; omit it for
 * booking-level cash shown on every MD row. Confirm on Movement
 * Dashboard only flips the row to collected. No receipt, and no
 * invoice allocation. Collected-by supplier cash then shows on
 * Supplier Collection; Own keeps the staff name on the row.
 */
export class CollectForMdDto {
  @IsUUID()
  booking_id: string;

  @IsOptional()
  @Transform(({ value }) => (value === '' || value === null ? undefined : value))
  @IsUUID()
  transport_item_id?: string;

  @IsEnum(CollectionPartyType)
  party_type: CollectionPartyType;

  @ValidateIf((o: CollectForMdDto) => o.party_type === CollectionPartyType.CUSTOMER)
  @IsString()
  @IsNotEmpty()
  @MaxLength(20)
  customer_mobile?: string;

  @ValidateIf((o: CollectForMdDto) => o.party_type === CollectionPartyType.SOURCE)
  @IsUUID()
  source_id?: string;

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

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

  @IsEnum(SettlementPaymentMode)
  mode: SettlementPaymentMode;

  /** 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)
  received_amount: number;

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

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

  /** Rate as entered in the natural "1 Bill = X Receive" direction,
   *  stored verbatim for display. */
  @IsNumber()
  @IsOptional()
  @Min(0)
  exchange_rate_quote?: number;

  @IsNumber()
  @IsOptional()
  @Min(0.01)
  received_amount_receive_currency?: number;

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

  /** Unused. MD cash is not allocated to customer or agent invoices. */
  @IsOptional()
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => PaymentAllocationDto)
  allocations?: PaymentAllocationDto[];

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

  @IsIn(['OWN', 'SUPPLIER'])
  collected_by_type: 'OWN' | 'SUPPLIER';

  @ValidateIf((o: CollectForMdDto) => o.collected_by_type === 'OWN')
  @IsString()
  @IsNotEmpty()
  @MaxLength(255)
  collector_name?: string;

  @ValidateIf((o: CollectForMdDto) => o.collected_by_type === 'SUPPLIER')
  @IsUUID()
  supplier_id?: string;

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

  @ValidateIf((o: CollectForMdDto) => o.collected_by_type === 'SUPPLIER' && !o.driver_id)
  @IsString()
  @IsNotEmpty()
  @MaxLength(255)
  driver_name?: string;
}
