import type { Transaction, Wallet } from '@core/payments/domain/entities/Wallet';
import { ReferenceType, Transaction as TransactionFactory, TransactionType, Wallet as WalletFactory } from '@core/payments/domain/entities/Wallet';

import { PaymentsTransactionOrmEntity } from '../entities/PaymentsTransactionOrmEntity';
import { PaymentsWalletOrmEntity } from '../entities/PaymentsWalletOrmEntity';
import {
    assertDate,
    assertEnumValue,
    assertNonEmptyString,
    assertNumber,
    assertOptionalStringOrNull,
} from '../schema/TypeOrmPaymentsSchemaGuards';

export class PaymentsWalletOrmMapper {
  toOrmEntity(domain: Wallet): PaymentsWalletOrmEntity {
    const entity = new PaymentsWalletOrmEntity();
    entity.id = domain.id;
    entity.leagueId = domain.leagueId;
    entity.balance = domain.balance;
    entity.totalRevenue = domain.totalRevenue;
    entity.totalPlatformFees = domain.totalPlatformFees;
    entity.totalWithdrawn = domain.totalWithdrawn;
    entity.currency = domain.currency;
    entity.createdAt = domain.createdAt;
    return entity;
  }

  toDomain(entity: PaymentsWalletOrmEntity): Wallet {
    const entityName = 'PaymentsWallet';

    assertNonEmptyString(entityName, 'id', entity.id);
    assertNonEmptyString(entityName, 'leagueId', entity.leagueId);
    assertNumber(entityName, 'balance', entity.balance);
    assertNumber(entityName, 'totalRevenue', entity.totalRevenue);
    assertNumber(entityName, 'totalPlatformFees', entity.totalPlatformFees);
    assertNumber(entityName, 'totalWithdrawn', entity.totalWithdrawn);
    assertNonEmptyString(entityName, 'currency', entity.currency);
    assertDate(entityName, 'createdAt', entity.createdAt);

    return WalletFactory.rehydrate({
      id: entity.id,
      leagueId: entity.leagueId,
      balance: entity.balance,
      totalRevenue: entity.totalRevenue,
      totalPlatformFees: entity.totalPlatformFees,
      totalWithdrawn: entity.totalWithdrawn,
      currency: entity.currency,
      createdAt: entity.createdAt,
    });
  }

  toOrmTransaction(domain: Transaction): PaymentsTransactionOrmEntity {
    const entity = new PaymentsTransactionOrmEntity();
    entity.id = domain.id;
    entity.walletId = domain.walletId;
    entity.type = domain.type;
    entity.amount = domain.amount;
    entity.description = domain.description;
    entity.referenceId = domain.referenceId ?? null;
    entity.referenceType = domain.referenceType ?? null;
    entity.createdAt = domain.createdAt;
    return entity;
  }

  toDomainTransaction(entity: PaymentsTransactionOrmEntity): Transaction {
    const entityName = 'PaymentsTransaction';

    assertNonEmptyString(entityName, 'id', entity.id);
    assertNonEmptyString(entityName, 'walletId', entity.walletId);
    assertNonEmptyString(entityName, 'type', entity.type);
    assertEnumValue(entityName, 'type', entity.type, Object.values(TransactionType));
    assertNumber(entityName, 'amount', entity.amount);
    assertNonEmptyString(entityName, 'description', entity.description);
    assertOptionalStringOrNull(entityName, 'referenceId', entity.referenceId);
    assertOptionalStringOrNull(entityName, 'referenceType', entity.referenceType);
    assertDate(entityName, 'createdAt', entity.createdAt);

    if (entity.referenceType !== null && entity.referenceType !== undefined) {
      assertEnumValue(entityName, 'referenceType', entity.referenceType, Object.values(ReferenceType));
    }

    return TransactionFactory.rehydrate({
      id: entity.id,
      walletId: entity.walletId,
      type: entity.type,
      amount: entity.amount,
      description: entity.description,
      createdAt: entity.createdAt,
      ...(entity.referenceId !== null && entity.referenceId !== undefined ? { referenceId: entity.referenceId } : {}),
      ...(entity.referenceType !== null && entity.referenceType !== undefined ? { referenceType: entity.referenceType as ReferenceType } : {}),
    });
  }
}
