/**
 * Validation decorators for request payload validation
 * using class-validator.
 */
import {
  IsString,
  IsNotEmpty,
  IsOptional,
  IsNumber,
  IsNumberString,
} from 'class-validator';

/**
 * Used to transform incoming payload values
 * (e.g., string → number) before validation.
 */
import { Type } from 'class-transformer';

/**
 * Swagger decorators for API documentation.
 */
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';

/**
 * Custom validator to accept either number or numeric string
 * with minimum value enforcement.
 */
import { IsNumberOrStringDto } from 'src/utils/common/numberOrStringDto';

/**
 * TaxDetailsDto
 * -------------
 * Represents individual tax breakdown items applied
 * to the bonus payment.
 *
 * Used as a nested object inside CreateBonusPaidDto.
 */
class TaxDetailsDto {
  /**
   * Name of the tax.
   *
   * Examples:
   * - GST
   * - TDS
   */
  @ApiPropertyOptional({ example: 'GST', description: 'Tax name' })
  @IsString()
  @IsOptional()
  tax_name?: string;

  /**
   * Tax percentage applied.
   *
   * Allows floating-point values.
   * Automatically converted to number using @Type.
   */
  @ApiPropertyOptional({
    example: 18.5,
    description: 'Tax percentage (float allowed)',
  })
  @Type(() => Number)
  @IsNumber({}, { message: 'Tax percentage must be a valid number' })
  @IsOptional()
  tax_per?: number;

  /**
   * Calculated tax amount.
   *
   * Allows floating-point values.
   * Transformed to number before validation.
   */
  @ApiPropertyOptional({
    example: 270.75,
    description: 'Tax amount (float allowed)',
  })
  @Type(() => Number)
  @IsNumber({}, { message: 'Tax amount must be a valid number' })
  @IsOptional()
  tax_amount?: number;
}

/**
 * CreateBonusPaidDto
 * ------------------
 * DTO used to create or update a bonus payment entry
 * for a sub-agent (associate).
 *
 * Handles:
 * - Monetary values
 * - Tax calculations
 * - Payment details
 * - Attachments
 */
export class CreateBonusPaidDto {
  /**
   * Optional record identifier.
   *
   * Used when updating an existing bonus record.
   */
  @ApiPropertyOptional({
    description: 'ID of the record',
    example: '9',
    type: String,
  })
  @IsOptional()
  @IsNumberString()
  id?: string;

  /**
   * Sub-agent (associate) identifier.
   *
   * Required field.
   */
  @ApiProperty({ example: 123, description: 'Sub-Agent (associate) ID' })
  @IsNumberString()
  @IsNotEmpty({ message: 'Associate ID is required' })
  associate_id: number | string;

  /**
   * Total bonus amount before deductions.
   *
   * Stored as string to preserve precision.
   */
  @ApiProperty({ example: '1500.50', description: 'Total amount' })
  @IsString()
  @IsNotEmpty({ message: 'Total amount is required' })
  total_amount: string;

  /**
   * Currency code for the transaction.
   *
   * Example:
   * - INR
   * - USD
   */
  @ApiPropertyOptional({
    example: 'USD',
    description: 'Currency code (3-5 characters)',
  })
  @IsString()
  @IsOptional({ message: 'Currency is required' })
  currency?: string;

  /**
   * Detailed tax breakdown.
   *
   * Contains an array of tax objects with
   * name, percentage, and amount.
   */
  @ApiPropertyOptional({
    type: [TaxDetailsDto],
    description: 'Array of tax details objects',
    example: [
      { tax_name: 'GST', tax_per: 18, tax_amount: 150 },
      { tax_name: 'TDS', tax_per: 10, tax_amount: 80 },
    ],
  })
  @IsOptional()
  @Type(() => TaxDetailsDto)
  tax_details?: TaxDetailsDto[];

  /**
   * Total tax amount applied.
   *
   * Optional pre-calculated value.
   */
  @ApiPropertyOptional({ example: '123.45', description: 'Total tax amount' })
  @IsOptional()
  @IsString()
  total_tax_amount?: string | null;

  /**
   * Other deductions applied to the bonus.
   */
  @ApiPropertyOptional({ example: '50.00', description: 'Other deductions' })
  @IsOptional()
  @IsString()
  other_deductions?: string | null;

  /**
   * Reason for additional deductions.
   */
  @ApiPropertyOptional({
    example: 'Some adjustment',
    description: 'Reason for other deductions',
  })
  @IsOptional()
  @IsString()
  deduction_reason?: string | null;

  /**
   * Final payable amount in INR after all deductions.
   *
   * Required field.
   */
  @ApiProperty({
    example: '123375.00',
    description: 'Net amount in INR after all deductions',
  })
  @IsString()
  @IsNotEmpty({ message: 'Net amount in INR is required' })
  net_amount_inr: string;

  /**
   * Date when payment was made.
   *
   * Format: YYYY-MM-DD
   */
  @ApiProperty({
    example: '2025-10-15',
    description: 'Payment date (YYYY-MM-DD)',
  })
  @IsString()
  @IsNotEmpty({ message: 'Payment date is required' })
  payment_date: string;

  /**
   * Payment mode identifier.
   *
   * Example:
   * - Bank Transfer
   * - Cash
   * - UPI
   */
  @ApiProperty({ example: 1, description: 'Payment mode (numeric value)' })
  @IsNumberString()
  @IsNotEmpty({ message: 'Payment mode is required' })
  payment_mode_id: number | string;

  /**
   * Source bank account ID.
   *
   * Represents company or system account.
   */
  @ApiPropertyOptional({
    example: 22,
    description: 'From bank account ID (WOSAL Account)',
  })
  @IsOptional()
  @IsNumberOrStringDto(1, 'From bank account ID')
  from_bank_account_id?: number | string | null;

  /**
   * Destination bank account ID.
   *
   * Represents sub-agent account.
   */
  @ApiPropertyOptional({
    example: 22,
    description: 'To bank account ID (Sub-Agent Account)',
  })
  @IsOptional()
  @IsNumberOrStringDto(1, 'To bank account ID')
  to_bank_account_id?: number | string | null;

  /**
   * Transaction reference number.
   *
   * Used for reconciliation and audit.
   */
  @ApiPropertyOptional({
    example: 'TXN123456789',
    description: 'Transaction ID/reference number',
  })
  @IsString()
  @IsOptional()
  transaction_id?: string;

  /**
   * Attachment files (plural).
   *
   * Typically contains screenshots or proof of payment.
   */
  @ApiPropertyOptional({
    type: [Object],
    description: 'Transaction screenshot',
  })
  @IsOptional()
  // @IsArray()
  attachment_files?: any[] | null;

  /**
   * Attachment file (singular).
   *
   * Kept for backward compatibility or alternate payload formats.
   */
  @ApiPropertyOptional({
    type: [Object],
    description: 'Transaction screenshot',
  })
  @IsOptional()
  // @IsArray()
  attachment_file?: any[] | null;

  /**
   * Additional remarks or notes.
   */
  @ApiPropertyOptional({
    example: 'Bonus Remarks',
    description: 'Remarks',
  })
  @IsOptional()
  @IsString()
  remarks?: string | null;
}
