import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNotEmpty, IsNumber, IsEnum, IsOptional, IsDate, IsBoolean } from 'class-validator';

export enum PaymentType {
  SPONSORSHIP = 'sponsorship',
  MEMBERSHIP_FEE = 'membership_fee',
}

export enum PayerType {
  SPONSOR = 'sponsor',
  DRIVER = 'driver',
}

export enum PaymentStatus {
  PENDING = 'pending',
  COMPLETED = 'completed',
  FAILED = 'failed',
  REFUNDED = 'refunded',
}

export class PaymentDto {
  @ApiProperty()
  @IsString()
  id!: string;

  @ApiProperty({ enum: PaymentType })
  @IsEnum(PaymentType)
  type!: PaymentType;

  @ApiProperty()
  @IsNumber()
  amount!: number;

  @ApiProperty()
  @IsNumber()
  platformFee!: number;

  @ApiProperty()
  @IsNumber()
  netAmount!: number;

  @ApiProperty()
  @IsString()
  payerId!: string;

  @ApiProperty({ enum: PayerType })
  @IsEnum(PayerType)
  payerType!: PayerType;

  @ApiProperty()
  @IsString()
  leagueId!: string;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  seasonId?: string;

  @ApiProperty({ enum: PaymentStatus })
  @IsEnum(PaymentStatus)
  status!: PaymentStatus;

  @ApiProperty()
  @IsDate()
  createdAt!: Date;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsDate()
  completedAt?: Date;
}

export class CreatePaymentInput {
  @ApiProperty({ enum: PaymentType })
  @IsEnum(PaymentType)
  type!: PaymentType;

  @ApiProperty()
  @IsNumber()
  amount!: number;

  @ApiProperty()
  @IsString()
  payerId!: string;

  @ApiProperty({ enum: PayerType })
  @IsEnum(PayerType)
  payerType!: PayerType;

  @ApiProperty()
  @IsString()
  leagueId!: string;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  seasonId?: string;
}

export class CreatePaymentOutput {
  @ApiProperty({ type: PaymentDto })
  payment!: PaymentDto;
}

export class UpdatePaymentStatusInput {
  @ApiProperty()
  @IsString()
  paymentId!: string;

  @ApiProperty({ enum: PaymentStatus })
  @IsEnum(PaymentStatus)
  status!: PaymentStatus;
}

export class UpdatePaymentStatusOutput {
  @ApiProperty({ type: PaymentDto })
  payment!: PaymentDto;
}

export enum MembershipFeeType {
  SEASON = 'season',
  MONTHLY = 'monthly',
  PER_RACE = 'per_race',
}

export enum MemberPaymentStatus {
  PENDING = 'pending',
  PAID = 'paid',
  OVERDUE = 'overdue',
}

export class MembershipFeeDto {
  @ApiProperty()
  @IsString()
  id!: string;

  @ApiProperty()
  @IsString()
  leagueId!: string;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  seasonId?: string;

  @ApiProperty({ enum: MembershipFeeType })
  @IsEnum(MembershipFeeType)
  type!: MembershipFeeType;

  @ApiProperty()
  @IsNumber()
  amount!: number;

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

  @ApiProperty()
  @IsDate()
  createdAt!: Date;

  @ApiProperty()
  @IsDate()
  updatedAt!: Date;
}

export class MemberPaymentDto {
  @ApiProperty()
  @IsString()
  id!: string;

  @ApiProperty()
  @IsString()
  feeId!: string;

  @ApiProperty()
  @IsString()
  driverId!: string;

  @ApiProperty()
  @IsNumber()
  amount!: number;

  @ApiProperty()
  @IsNumber()
  platformFee!: number;

  @ApiProperty()
  @IsNumber()
  netAmount!: number;

  @ApiProperty({ enum: MemberPaymentStatus })
  @IsEnum(MemberPaymentStatus)
  status!: MemberPaymentStatus;

  @ApiProperty()
  @IsDate()
  dueDate!: Date;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsDate()
  paidAt?: Date;
}

export class GetMembershipFeesQuery {
  @ApiProperty()
  @IsString()
  leagueId!: string;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  driverId?: string;
}

export class GetMembershipFeesOutput {
  @ApiProperty({ type: MembershipFeeDto, nullable: true })
  fee!: MembershipFeeDto | null;

  @ApiProperty({ type: [MemberPaymentDto] })
  payments!: MemberPaymentDto[];
}

export class UpsertMembershipFeeInput {
  @ApiProperty()
  @IsString()
  leagueId!: string;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  seasonId?: string;

  @ApiProperty({ enum: MembershipFeeType })
  @IsEnum(MembershipFeeType)
  type!: MembershipFeeType;

  @ApiProperty()
  @IsNumber()
  amount!: number;
}

export class UpsertMembershipFeeOutput {
  @ApiProperty({ type: MembershipFeeDto })
  fee!: MembershipFeeDto;
}

export class UpdateMemberPaymentInput {
  @ApiProperty()
  @IsString()
  feeId!: string;

  @ApiProperty()
  @IsString()
  driverId!: string;

  @ApiProperty({ required: false, enum: MemberPaymentStatus })
  @IsOptional()
  @IsEnum(MemberPaymentStatus)
  status?: MemberPaymentStatus;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsDate()
  paidAt?: Date | string;
}

export class UpdateMemberPaymentOutput {
  @ApiProperty({ type: MemberPaymentDto })
  payment!: MemberPaymentDto;
}

export class GetPaymentsQuery {
  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  leagueId?: string;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  payerId?: string;

  @ApiProperty({ required: false, enum: PaymentType })
  @IsOptional()
  @IsEnum(PaymentType)
  type?: PaymentType;
}

export class GetPaymentsOutput {
  @ApiProperty({ type: [PaymentDto] })
  payments!: PaymentDto[];
}

export enum PrizeType {
  CASH = 'cash',
  MERCHANDISE = 'merchandise',
  OTHER = 'other',
}

export class PrizeDto {
  @ApiProperty()
  @IsString()
  id!: string;

  @ApiProperty()
  @IsString()
  leagueId!: string;

  @ApiProperty()
  @IsString()
  seasonId!: string;

  @ApiProperty()
  @IsNumber()
  position!: number;

  @ApiProperty()
  @IsString()
  name!: string;

  @ApiProperty()
  @IsNumber()
  amount!: number;

  @ApiProperty({ enum: PrizeType })
  @IsEnum(PrizeType)
  type!: PrizeType;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  description?: string;

  @ApiProperty()
  @IsBoolean()
  awarded!: boolean;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  awardedTo?: string;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsDate()
  awardedAt?: Date;

  @ApiProperty()
  @IsDate()
  createdAt!: Date;
}

export class GetPrizesQuery {
  @ApiProperty()
  @IsString()
  leagueId?: string;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  seasonId?: string;
}

export class GetPrizesOutput {
  @ApiProperty({ type: [PrizeDto] })
  prizes!: PrizeDto[];
}

export class CreatePrizeInput {
  @ApiProperty()
  @IsString()
  leagueId!: string;

  @ApiProperty()
  @IsString()
  seasonId!: string;

  @ApiProperty()
  @IsNumber()
  position!: number;

  @ApiProperty()
  @IsString()
  name!: string;

  @ApiProperty()
  @IsNumber()
  amount!: number;

  @ApiProperty({ enum: PrizeType })
  @IsEnum(PrizeType)
  type!: PrizeType;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  description?: string;
}

export class CreatePrizeOutput {
  @ApiProperty({ type: PrizeDto })
  prize!: PrizeDto;
}

export class AwardPrizeInput {
  @ApiProperty()
  @IsString()
  prizeId!: string;

  @ApiProperty()
  @IsString()
  driverId!: string;
}

export class AwardPrizeOutput {
  @ApiProperty({ type: PrizeDto })
  prize!: PrizeDto;
}

export class DeletePrizeInput {
  @ApiProperty()
  @IsString()
  prizeId!: string;
}

export class DeletePrizeOutput {
  @ApiProperty()
  @IsBoolean()
  success!: boolean;
}

export enum TransactionType {
  DEPOSIT = 'deposit',
  WITHDRAWAL = 'withdrawal',
  PLATFORM_FEE = 'platform_fee',
}

export enum ReferenceType {
  SPONSORSHIP = 'sponsorship',
  MEMBERSHIP_FEE = 'membership_fee',
  PRIZE = 'prize',
}

export class WalletDto {
  @ApiProperty()
  @IsString()
  id!: string;

  @ApiProperty()
  @IsString()
  leagueId!: string;

  @ApiProperty()
  @IsNumber()
  balance!: number;

  @ApiProperty()
  @IsNumber()
  totalRevenue!: number;

  @ApiProperty()
  @IsNumber()
  totalPlatformFees!: number;

  @ApiProperty()
  @IsNumber()
  totalWithdrawn!: number;

  @ApiProperty()
  @IsDate()
  createdAt!: Date;

  @ApiProperty()
  @IsString()
  currency!: string;
}

export class TransactionDto {
  @ApiProperty()
  @IsString()
  id!: string;

  @ApiProperty()
  @IsString()
  walletId!: string;

  @ApiProperty({ enum: TransactionType })
  @IsEnum(TransactionType)
  type!: TransactionType;

  @ApiProperty()
  @IsNumber()
  amount!: number;

  @ApiProperty()
  @IsString()
  description!: string;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  referenceId?: string;

  @ApiProperty({ required: false, enum: ReferenceType })
  @IsOptional()
  @IsEnum(ReferenceType)
  referenceType?: ReferenceType;

  @ApiProperty()
  @IsDate()
  createdAt!: Date;
}

export class GetWalletQuery {
  @ApiProperty()
  @IsString()
  leagueId?: string;
}

export class GetWalletOutput {
  @ApiProperty({ type: WalletDto })
  wallet!: WalletDto;

  @ApiProperty({ type: [TransactionDto] })
  transactions!: TransactionDto[];
}

export class ProcessWalletTransactionInput {
  @ApiProperty()
  @IsString()
  leagueId!: string;

  @ApiProperty({ enum: TransactionType })
  @IsEnum(TransactionType)
  type!: TransactionType;

  @ApiProperty()
  @IsNumber()
  amount!: number;

  @ApiProperty()
  @IsString()
  @IsNotEmpty()
  description!: string;

  @ApiProperty({ required: false })
  @IsOptional()
  @IsString()
  referenceId?: string;

  @ApiProperty({ required: false, enum: ReferenceType })
  @IsOptional()
  @IsEnum(ReferenceType)
  referenceType?: ReferenceType;
}

export class ProcessWalletTransactionOutput {
  @ApiProperty({ type: WalletDto })
  wallet!: WalletDto;

  @ApiProperty({ type: TransactionDto })
  transaction!: TransactionDto;
}