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

export enum NationalityType {
  LOCAL = 'LOCAL',
  INTERNATIONAL = 'INTERNATIONAL'
}

export enum CoachType {
  REGULAR_SEAT = 'REGULAR_SEAT',
  ECONOMY_BED = 'ECONOMY_BED',
  VIP_BED = 'VIP_BED'
}

export enum BedPosition {
  UPPER = 'UPPER',
  MIDDLE = 'MIDDLE',
  LOWER = 'LOWER'
}

export enum ComponentType {
  INSURANCE = 'INSURANCE',
  PREMIUM = 'PREMIUM',
  SERVICE_CHARGE = 'SERVICE_CHARGE',
  TAX = 'TAX',
  DEMAND = 'DEMAND'
}

export enum CalculationMethod {
  MULTIPLIER = 'MULTIPLIER',
  PERCENTAGE = 'PERCENTAGE',
  FIXED_AMOUNT = 'FIXED_AMOUNT'
}

export enum AppliesTo {
  BASE_FARE = 'BASE_FARE',
  SUBTOTAL = 'SUBTOTAL',
  TOTAL = 'TOTAL'
}

export enum PricingType {
  FREE = 'FREE',
  FULL_FARE = 'FULL_FARE',
  DISCOUNTED = 'DISCOUNTED'
}

export class FareRateRuleDto {
  @ApiProperty({ enum: NationalityType })
  @IsEnum(NationalityType)
  nationalityType: NationalityType;

  @ApiProperty({ enum: CoachType })
  @IsEnum(CoachType)
  coachType: CoachType;

  @ApiPropertyOptional({ enum: BedPosition })
  @IsOptional()
  @IsEnum(BedPosition)
  bedPosition?: BedPosition;

  @ApiProperty({ example: 3000, description: 'Rate per km in minor units (e.g., 30.00 ETB = 3000)' })
  @IsInt()
  @Min(0)
  ratePerKmMinor: number;

  @ApiPropertyOptional({ default: true })
  @IsOptional()
  @IsBoolean()
  isActive?: boolean;
}

export class FareComponentDto {
  @ApiProperty({ enum: ComponentType })
  @IsEnum(ComponentType)
  componentType: ComponentType;

  @ApiProperty({ example: 'Travel Insurance' })
  @IsString()
  componentName: string;

  @ApiProperty({ enum: CalculationMethod })
  @IsEnum(CalculationMethod)
  calculationMethod: CalculationMethod;

  @ApiPropertyOptional({ example: 500, description: 'Fixed amount in minor units' })
  @IsOptional()
  @IsInt()
  @Min(0)
  valueMinor?: number;

  @ApiPropertyOptional({ example: 0.02, description: 'Percentage value (e.g., 0.02 for 2%)' })
  @IsOptional()
  @IsNumber()
  @Min(0)
  @Max(1)
  percentageValue?: number;

  @ApiProperty({ enum: AppliesTo, default: AppliesTo.SUBTOTAL })
  @IsEnum(AppliesTo)
  appliesTo: AppliesTo;

  @ApiProperty({ example: 1, description: 'Order of application' })
  @IsInt()
  @Min(1)
  applyOrder: number;

  @ApiPropertyOptional({ default: true })
  @IsOptional()
  @IsBoolean()
  isActive?: boolean;
}

export class AgePricingRuleDto {
  @ApiProperty({ example: 'Adult Passengers' })
  @IsString()
  ruleName: string;

  @ApiProperty({ example: 5 })
  @IsInt()
  @Min(0)
  minAge: number;

  @ApiPropertyOptional({ example: 120 })
  @IsOptional()
  @IsInt()
  @Min(0)
  maxAge?: number;

  @ApiProperty({ enum: PricingType })
  @IsEnum(PricingType)
  pricingType: PricingType;

  @ApiPropertyOptional({ example: 0.5, description: 'Discount percentage for DISCOUNTED type' })
  @IsOptional()
  @IsNumber()
  @Min(0)
  @Max(1)
  discountPercentage?: number;

  @ApiPropertyOptional({ example: 1, description: 'Max free passengers for FREE type' })
  @IsOptional()
  @IsInt()
  @Min(0)
  maxFreePassengers?: number;

  @ApiPropertyOptional({ default: false })
  @IsOptional()
  @IsBoolean()
  appliesToComponents?: boolean;

  @ApiPropertyOptional({ default: true })
  @IsOptional()
  @IsBoolean()
  isActive?: boolean;
}

export class CreateFareConfigurationDto {
  @ApiProperty({ example: 'Summer 2024 Rates' })
  @IsString()
  name: string;

  @ApiPropertyOptional({ example: 'Updated rates for summer season' })
  @IsOptional()
  @IsString()
  description?: string;

  @ApiProperty({ example: '2024-06-01T00:00:00.000Z' })
  @IsDateString()
  effectiveDate: string;

  @ApiPropertyOptional({ example: '2024-08-31T23:59:59.000Z' })
  @IsOptional()
  @IsDateString()
  expiryDate?: string;

  @ApiProperty({ type: [FareRateRuleDto] })
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => FareRateRuleDto)
  rateRules: FareRateRuleDto[];

  @ApiProperty({ type: [FareComponentDto] })
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => FareComponentDto)
  components: FareComponentDto[];

  @ApiProperty({ type: [AgePricingRuleDto] })
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => AgePricingRuleDto)
  ageRules: AgePricingRuleDto[];

  @ApiPropertyOptional({ default: false })
  @IsOptional()
  @IsBoolean()
  isDefault?: boolean;
}

export class UpdateFareConfigurationDto {
  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  name?: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  description?: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsDateString()
  effectiveDate?: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsDateString()
  expiryDate?: string;

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

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

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

export class FareTestScenarioDto {
  @ApiProperty({ example: 100 })
  @IsInt()
  @Min(1)
  distanceKm: number;

  @ApiProperty({ example: 'Ethiopian' })
  @IsString()
  nationality: string;

  @ApiProperty({ enum: CoachType })
  @IsEnum(CoachType)
  coachType: CoachType;

  @ApiPropertyOptional({ enum: BedPosition })
  @IsOptional()
  @IsEnum(BedPosition)
  bedPosition?: BedPosition;

  @ApiProperty({ example: 2, default: 1 })
  @IsInt()
  @Min(1)
  adultCount: number;

  @ApiPropertyOptional({ example: 1, default: 0 })
  @IsOptional()
  @IsInt()
  @Min(0)
  childCount?: number;

  @ApiPropertyOptional({ example: 'SUMMER20' })
  @IsOptional()
  @IsString()
  promoCode?: string;

  @ApiPropertyOptional({ example: 500 })
  @IsOptional()
  @IsInt()
  @Min(0)
  loyaltyPoints?: number;
}

export class FareCalculationResultDto {
  @ApiProperty()
  baseFareMinor: number;

  @ApiProperty()
  componentsTotal: number;

  @ApiProperty()
  totalBeforeDiscounts: number;

  @ApiProperty()
  discountsTotal: number;

  @ApiProperty()
  finalTotalMinor: number;

  @ApiProperty()
  breakdown: Array<{
    step: string;
    description: string;
    amount: number;
    runningTotal: number;
  }>;

  @ApiProperty()
  currency: string;

  @ApiProperty()
  calculationTimestamp: Date;
}

export class MigrateLegacyDto {
  @ApiPropertyOptional({ default: false })
  @IsOptional()
  @IsBoolean()
  dryRun?: boolean;

  @ApiPropertyOptional({ default: true })
  @IsOptional()
  @IsBoolean()
  migrateScheduleFares?: boolean;

  @ApiPropertyOptional({ default: true })
  @IsOptional()
  @IsBoolean()
  migrateSegmentFares?: boolean;
}

export class CreateNewFormulaDto {
  @ApiProperty({ example: 'Default Formula Configuration' })
  @IsString()
  name: string;

  @ApiPropertyOptional({ example: 'System-generated default configuration' })
  @IsOptional()
  @IsString()
  description?: string;

  @ApiPropertyOptional({ default: true })
  @IsOptional()
  @IsBoolean()
  activateImmediately?: boolean;
}

export class ToggleFeatureDto {
  @ApiProperty({ example: 'USE_CONFIGURABLE_FARES' })
  @IsString()
  featureName: string;

  @ApiProperty()
  @IsBoolean()
  enabled: boolean;

  @ApiPropertyOptional({ example: { rollout_percentage: 50 } })
  @IsOptional()
  config?: Record<string, any>;
}