"""
Tests for transaction type constants and helper functions.
"""
from django.test import TestCase

from wallet_utils.transaction_types import (
    # Wallet Operations
    WALLET_DEPOSIT,
    WALLET_DEPOSIT_CANCEL,
    WALLET_TRANSFER,
    WALLET_WITHDRAW,
    WALLET_WITHDRAW_REFUND,
    WALLET_ADJUST,
    WALLET_TOPUP,
    WALLET_DEDUCT,
    # Package Operations
    PACKAGE_ACTIVATION,
    PACKAGE_ACTIVATION_CANCEL,
    PACKAGE_UPGRADE,
    PACKAGE_UPGRADE_CANCEL,
    PACKAGE_RENEWAL,
    PACKAGE_RENEWAL_CANCEL,
    PACKAGE_EXPIRY_REFUND,
    # Commission & Rewards
    COMMISSION_DISTRIBUTION,
    COMMISSION_DISTRIBUTION_REVERSE,
    ROI_DISTRIBUTION,
    ROI_DISTRIBUTION_REVERSE,
    REFERRAL_BONUS,
    REFERRAL_BONUS_REVERSE,
    MATCHING_BONUS,
    MATCHING_BONUS_REVERSE,
    LEADERSHIP_BONUS,
    LEADERSHIP_BONUS_REVERSE,
    PROMOTION_BONUS,
    PROMOTION_BONUS_REVERSE,
    # Product Operations
    PRODUCT_ORDER,
    PRODUCT_ORDER_CANCEL,
    PRODUCT_ORDER_REFUND,
    PRODUCT_REDEMPTION,
    PRODUCT_REDEMPTION_CANCEL,
    PRODUCT_EXCHANGE,
    PRODUCT_EXCHANGE_REVERSE,
    # System Operations
    SYSTEM_ADJUSTMENT,
    SYSTEM_REWARD,
    SYSTEM_PENALTY,
    SYSTEM_REVERSAL,
    SYSTEM_MIGRATION,
    # Payment Operations
    PAYMENT_RECEIVED,
    PAYMENT_REFUND,
    PAYMENT_FAILED_REFUND,
    PAYMENT_CHARGEBACK,
    PAYMENT_CHARGEBACK_REVERSAL,
    # Loan & Credit Operations
    LOAN_DISBURSEMENT,
    LOAN_REPAYMENT,
    LOAN_WRITE_OFF,
    CREDIT_LIMIT_INCREASE,
    CREDIT_LIMIT_DECREASE,
    # Exchange & Conversion
    CURRENCY_EXCHANGE,
    POINT_CONVERSION,
    POINT_CONVERSION_REVERSE,
    BONUS_CONVERSION,
    BONUS_CONVERSION_REVERSE,
    # Fee Operations
    TRANSACTION_FEE,
    TRANSACTION_FEE_REFUND,
    WITHDRAWAL_FEE,
    WITHDRAWAL_FEE_REFUND,
    TRANSFER_FEE,
    TRANSFER_FEE_REFUND,
    MAINTENANCE_FEE,
    MAINTENANCE_FEE_REFUND,
    # Helper functions and dictionaries
    TRANSACTION_TYPES,
    TRANSACTION_TYPE_NAMES,
    get_transaction_type,
    get_transaction_type_name,
)


class TransactionTypeConstantsTests(TestCase):
    """Tests for transaction type constants."""
    
    def test_wallet_operations_constants(self):
        """Test wallet operation constants."""
        self.assertEqual(WALLET_DEPOSIT, 1000)
        self.assertEqual(WALLET_DEPOSIT_CANCEL, 1001)
        self.assertEqual(WALLET_TRANSFER, 1002)
        self.assertEqual(WALLET_WITHDRAW, 1003)
        self.assertEqual(WALLET_WITHDRAW_REFUND, 1004)
        self.assertEqual(WALLET_ADJUST, 1005)
        self.assertEqual(WALLET_TOPUP, 1006)
        self.assertEqual(WALLET_DEDUCT, 1007)
        
        # Verify they're integers
        self.assertIsInstance(WALLET_DEPOSIT, int)
        self.assertIsInstance(WALLET_WITHDRAW, int)
    
    def test_package_operations_constants(self):
        """Test package operation constants."""
        self.assertEqual(PACKAGE_ACTIVATION, 2000)
        self.assertEqual(PACKAGE_ACTIVATION_CANCEL, 2001)
        self.assertEqual(PACKAGE_UPGRADE, 2002)
        self.assertEqual(PACKAGE_UPGRADE_CANCEL, 2003)
        self.assertEqual(PACKAGE_RENEWAL, 2004)
        self.assertEqual(PACKAGE_RENEWAL_CANCEL, 2005)
        self.assertEqual(PACKAGE_EXPIRY_REFUND, 2006)
    
    def test_commission_rewards_constants(self):
        """Test commission and rewards constants."""
        self.assertEqual(COMMISSION_DISTRIBUTION, 3000)
        self.assertEqual(COMMISSION_DISTRIBUTION_REVERSE, 3001)
        self.assertEqual(ROI_DISTRIBUTION, 3100)
        self.assertEqual(ROI_DISTRIBUTION_REVERSE, 3101)
        self.assertEqual(REFERRAL_BONUS, 3200)
        self.assertEqual(REFERRAL_BONUS_REVERSE, 3201)
        self.assertEqual(MATCHING_BONUS, 3300)
        self.assertEqual(MATCHING_BONUS_REVERSE, 3301)
        self.assertEqual(LEADERSHIP_BONUS, 3400)
        self.assertEqual(LEADERSHIP_BONUS_REVERSE, 3401)
        self.assertEqual(PROMOTION_BONUS, 3500)
        self.assertEqual(PROMOTION_BONUS_REVERSE, 3501)
    
    def test_product_operations_constants(self):
        """Test product operation constants."""
        self.assertEqual(PRODUCT_ORDER, 4000)
        self.assertEqual(PRODUCT_ORDER_CANCEL, 4001)
        self.assertEqual(PRODUCT_ORDER_REFUND, 4002)
        self.assertEqual(PRODUCT_REDEMPTION, 4003)
        self.assertEqual(PRODUCT_REDEMPTION_CANCEL, 4004)
        self.assertEqual(PRODUCT_EXCHANGE, 4005)
        self.assertEqual(PRODUCT_EXCHANGE_REVERSE, 4006)
    
    def test_system_operations_constants(self):
        """Test system operation constants."""
        self.assertEqual(SYSTEM_ADJUSTMENT, 5000)
        self.assertEqual(SYSTEM_REWARD, 5001)
        self.assertEqual(SYSTEM_PENALTY, 5002)
        self.assertEqual(SYSTEM_REVERSAL, 5003)
        self.assertEqual(SYSTEM_MIGRATION, 5004)
    
    def test_payment_operations_constants(self):
        """Test payment operation constants."""
        self.assertEqual(PAYMENT_RECEIVED, 6000)
        self.assertEqual(PAYMENT_REFUND, 6001)
        self.assertEqual(PAYMENT_FAILED_REFUND, 6002)
        self.assertEqual(PAYMENT_CHARGEBACK, 6003)
        self.assertEqual(PAYMENT_CHARGEBACK_REVERSAL, 6004)
    
    def test_loan_credit_constants(self):
        """Test loan and credit constants."""
        self.assertEqual(LOAN_DISBURSEMENT, 7000)
        self.assertEqual(LOAN_REPAYMENT, 7001)
        self.assertEqual(LOAN_WRITE_OFF, 7002)
        self.assertEqual(CREDIT_LIMIT_INCREASE, 7003)
        self.assertEqual(CREDIT_LIMIT_DECREASE, 7004)
    
    def test_exchange_conversion_constants(self):
        """Test exchange and conversion constants."""
        self.assertEqual(CURRENCY_EXCHANGE, 8000)
        self.assertEqual(POINT_CONVERSION, 8001)
        self.assertEqual(POINT_CONVERSION_REVERSE, 8002)
        self.assertEqual(BONUS_CONVERSION, 8003)
        self.assertEqual(BONUS_CONVERSION_REVERSE, 8004)
    
    def test_fee_operations_constants(self):
        """Test fee operation constants."""
        self.assertEqual(TRANSACTION_FEE, 9000)
        self.assertEqual(TRANSACTION_FEE_REFUND, 9001)
        self.assertEqual(WITHDRAWAL_FEE, 9002)
        self.assertEqual(WITHDRAWAL_FEE_REFUND, 9003)
        self.assertEqual(TRANSFER_FEE, 9004)
        self.assertEqual(TRANSFER_FEE_REFUND, 9005)
        self.assertEqual(MAINTENANCE_FEE, 9006)
        self.assertEqual(MAINTENANCE_FEE_REFUND, 9007)
    
    def test_constant_ranges(self):
        """Test that constants are in expected ranges."""
        # Wallet Operations: 1000-1999
        self.assertGreaterEqual(WALLET_DEPOSIT, 1000)
        self.assertLess(WALLET_DEDUCT, 2000)
        
        # Package Operations: 2000-2999
        self.assertGreaterEqual(PACKAGE_ACTIVATION, 2000)
        self.assertLess(PACKAGE_EXPIRY_REFUND, 3000)
        
        # Commission & Rewards: 3000-3999
        self.assertGreaterEqual(COMMISSION_DISTRIBUTION, 3000)
        self.assertLess(PROMOTION_BONUS_REVERSE, 4000)
        
        # Product Operations: 4000-4999
        self.assertGreaterEqual(PRODUCT_ORDER, 4000)
        self.assertLess(PRODUCT_EXCHANGE_REVERSE, 5000)
        
        # System Operations: 5000-5999
        self.assertGreaterEqual(SYSTEM_ADJUSTMENT, 5000)
        self.assertLess(SYSTEM_MIGRATION, 6000)
        
        # Payment Operations: 6000-6999
        self.assertGreaterEqual(PAYMENT_RECEIVED, 6000)
        self.assertLess(PAYMENT_CHARGEBACK_REVERSAL, 7000)
        
        # Loan & Credit: 7000-7999
        self.assertGreaterEqual(LOAN_DISBURSEMENT, 7000)
        self.assertLess(CREDIT_LIMIT_DECREASE, 8000)
        
        # Exchange & Conversion: 8000-8999
        self.assertGreaterEqual(CURRENCY_EXCHANGE, 8000)
        self.assertLess(BONUS_CONVERSION_REVERSE, 9000)
        
        # Fee Operations: 9000-9999
        self.assertGreaterEqual(TRANSACTION_FEE, 9000)
        self.assertLess(MAINTENANCE_FEE_REFUND, 10000)


class TransactionTypeHelperFunctionsTests(TestCase):
    """Tests for transaction type helper functions."""
    
    def test_get_transaction_type_valid(self):
        """Test get_transaction_type() with valid names."""
        self.assertEqual(get_transaction_type("wallet-deposit"), 1000)
        self.assertEqual(get_transaction_type("wallet-withdraw"), 1003)
        self.assertEqual(get_transaction_type("roi-distribution"), 3100)
        self.assertEqual(get_transaction_type("referral-bonus"), 3200)
        self.assertEqual(get_transaction_type("system-adjustment"), 5000)
    
    def test_get_transaction_type_invalid(self):
        """Test get_transaction_type() with invalid name."""
        with self.assertRaises(ValueError) as cm:
            get_transaction_type("invalid-type")
        
        self.assertIn("Unknown transaction type", str(cm.exception))
    
    def test_get_transaction_type_name_valid(self):
        """Test get_transaction_type_name() with valid constants."""
        self.assertEqual(get_transaction_type_name(1000), "wallet-deposit")
        self.assertEqual(get_transaction_type_name(1003), "wallet-withdraw")
        self.assertEqual(get_transaction_type_name(3100), "roi-distribution")
        self.assertEqual(get_transaction_type_name(3200), "referral-bonus")
        self.assertEqual(get_transaction_type_name(5000), "system-adjustment")
    
    def test_get_transaction_type_name_invalid(self):
        """Test get_transaction_type_name() with invalid constant."""
        self.assertIsNone(get_transaction_type_name(99999))
        self.assertIsNone(get_transaction_type_name(0))
        self.assertIsNone(get_transaction_type_name(-1))
    
    def test_transaction_types_dictionary(self):
        """Test TRANSACTION_TYPES dictionary."""
        self.assertIn("wallet-deposit", TRANSACTION_TYPES)
        self.assertEqual(TRANSACTION_TYPES["wallet-deposit"], 1000)
        self.assertIn("roi-distribution", TRANSACTION_TYPES)
        self.assertEqual(TRANSACTION_TYPES["roi-distribution"], 3100)
    
    def test_transaction_type_names_dictionary(self):
        """Test TRANSACTION_TYPE_NAMES dictionary."""
        self.assertIn(1000, TRANSACTION_TYPE_NAMES)
        self.assertEqual(TRANSACTION_TYPE_NAMES[1000], "wallet-deposit")
        self.assertIn(3100, TRANSACTION_TYPE_NAMES)
        self.assertEqual(TRANSACTION_TYPE_NAMES[3100], "roi-distribution")
    
    def test_dictionary_consistency(self):
        """Test that TRANSACTION_TYPES and TRANSACTION_TYPE_NAMES are consistent."""
        for name, trans_type in TRANSACTION_TYPES.items():
            self.assertEqual(TRANSACTION_TYPE_NAMES[trans_type], name)
        
        for trans_type, name in TRANSACTION_TYPE_NAMES.items():
            self.assertEqual(TRANSACTION_TYPES[name], trans_type)
    
    def test_all_constants_in_dictionary(self):
        """Test that all constants are in the dictionaries."""
        constants = [
            WALLET_DEPOSIT, WALLET_WITHDRAW, ROI_DISTRIBUTION,
            REFERRAL_BONUS, SYSTEM_ADJUSTMENT, PRODUCT_ORDER,
        ]
        
        for constant in constants:
            self.assertIn(constant, TRANSACTION_TYPE_NAMES)
            name = TRANSACTION_TYPE_NAMES[constant]
            self.assertIn(name, TRANSACTION_TYPES)
            self.assertEqual(TRANSACTION_TYPES[name], constant)
