// pezkuwi/pallets/pez-treasury/src/tests.rs

use crate::{mock::*, Error, Event};
use frame_support::{assert_noop, assert_ok};
use sp_runtime::traits::Zero; // FIXED: Import Zero trait for is_zero() method

// =============================================================================
// 1. GENESIS DISTRIBUTION TESTS
// =============================================================================

#[test]
fn genesis_distribution_works() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());

        let treasury_amount = 4_812_500_000 * 1_000_000_000_000u128;
        let presale_amount = 93_750_000 * 1_000_000_000_000u128;
        let founder_amount = 93_750_000 * 1_000_000_000_000u128;

        assert_pez_balance(treasury_account(), treasury_amount);
        assert_pez_balance(presale(), presale_amount);
        assert_pez_balance(founder(), founder_amount);

        let total = treasury_amount + presale_amount + founder_amount;
        assert_eq!(total, 5_000_000_000 * 1_000_000_000_000u128);

        System::assert_has_event(
            Event::GenesisDistributionCompleted {
                treasury_amount,
                presale_amount,
                founder_amount,
            }
            .into(),
        );
    });
}

#[test]
fn force_genesis_distribution_requires_root() {
    new_test_ext().execute_with(|| {
        assert_noop!(
            PezTreasury::force_genesis_distribution(RuntimeOrigin::signed(alice())),
            sp_runtime::DispatchError::BadOrigin
        );
    });
}

#[test]
fn force_genesis_distribution_works_with_root() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::force_genesis_distribution(RuntimeOrigin::root()));

        assert!(Assets::balance(PezAssetId::get(), treasury_account()) > 0);
        assert!(Assets::balance(PezAssetId::get(), presale()) > 0);
        assert!(Assets::balance(PezAssetId::get(), founder()) > 0);
    });
}

#[test]
fn genesis_distribution_can_only_happen_once() {
    new_test_ext().execute_with(|| {
        // First call should succeed
        assert_ok!(PezTreasury::do_genesis_distribution());

        // Verify flag is set
        assert!(PezTreasury::genesis_distribution_done());

        // Second call should fail
        assert_noop!(
            PezTreasury::do_genesis_distribution(),
            Error::<Test>::GenesisDistributionAlreadyDone
        );

        // Verify balances didn't double
        let treasury_amount = 4_812_500_000 * 1_000_000_000_000u128;
        assert_pez_balance(treasury_account(), treasury_amount);
    });
}

// =============================================================================
// 2. TREASURY INITIALIZATION TESTS
// =============================================================================

#[test]
fn initialize_treasury_works() {
    new_test_ext().execute_with(|| {
        let start_block = System::block_number();

        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        // Verify storage
        assert_eq!(
            PezTreasury::treasury_start_block(),
            Some(start_block)
        );

        let halving_info = PezTreasury::halving_info();
        assert_eq!(halving_info.current_period, 0);
        assert_eq!(halving_info.period_start_block, start_block);
        assert!(!halving_info.monthly_amount.is_zero());

        // Verify next release month
        assert_eq!(PezTreasury::next_release_month(), 0);

        // Verify event
        System::assert_has_event(
            Event::TreasuryInitialized {
                start_block,
                initial_monthly_amount: halving_info.monthly_amount,
            }
            .into(),
        );
    });
}

#[test]
fn initialize_treasury_fails_if_already_initialized() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        // Try to initialize again
        assert_noop!(
            PezTreasury::initialize_treasury(RuntimeOrigin::root()),
            Error::<Test>::TreasuryAlreadyInitialized
        );
    });
}

#[test]
fn initialize_treasury_requires_root() {
    new_test_ext().execute_with(|| {
        assert_noop!(
            PezTreasury::initialize_treasury(RuntimeOrigin::signed(alice())),
            sp_runtime::DispatchError::BadOrigin
        );
    });
}

#[test]
fn initialize_treasury_calculates_correct_monthly_amount() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let halving_info = PezTreasury::halving_info();
        
        // First period total = 96.25% / 2 = 48.125%
        let treasury_total = 4_812_500_000 * 1_000_000_000_000u128;
        let first_period = treasury_total / 2;
        let expected_monthly = first_period / 48; // 48 months

        assert_eq!(halving_info.monthly_amount, expected_monthly);
    });
}

// =============================================================================
// 3. MONTHLY RELEASE TESTS
// =============================================================================

#[test]
fn release_monthly_funds_works() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let initial_monthly = PezTreasury::halving_info().monthly_amount;
        let incentive_expected = initial_monthly * 75 / 100;
        let government_expected = initial_monthly - incentive_expected;

        run_to_block(432_001);

        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        assert_pez_balance(PezTreasury::incentive_pot_account_id(), incentive_expected);
        assert_pez_balance(PezTreasury::government_pot_account_id(), government_expected);

        assert_eq!(PezTreasury::next_release_month(), 1);

        let halving_info = PezTreasury::halving_info();
        assert_eq!(halving_info.total_released, initial_monthly);
    });
}

#[test]
fn release_monthly_funds_fails_if_not_initialized() {
    new_test_ext().execute_with(|| {
        assert_noop!(
            PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
            Error::<Test>::TreasuryNotInitialized
        );
    });
}

#[test]
fn release_monthly_funds_fails_if_too_early() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        // Try to release before time
        run_to_block(100);

        assert_noop!(
            PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
            Error::<Test>::ReleaseTooEarly
        );
    });
}

#[test]
fn release_monthly_funds_fails_if_already_released() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        run_to_block(432_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        // Try to release same month again
        assert_noop!(
            PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
            Error::<Test>::ReleaseTooEarly
        );
    });
}

#[test]
fn release_monthly_funds_splits_correctly() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let monthly_amount = PezTreasury::halving_info().monthly_amount;

        run_to_block(432_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        let incentive_balance = Assets::balance(PezAssetId::get(), PezTreasury::incentive_pot_account_id());
        let government_balance = Assets::balance(PezAssetId::get(), PezTreasury::government_pot_account_id());

        // 75% to incentive, 25% to government
        assert_eq!(incentive_balance, monthly_amount * 75 / 100);
        // lib.rs'deki mantıkla aynı olmalı (saturating_sub)
		let incentive_amount_calculated = monthly_amount * 75 / 100;
		assert_eq!(government_balance, monthly_amount - incentive_amount_calculated);
        
        // Total should equal monthly amount
        assert_eq!(incentive_balance + government_balance, monthly_amount);
    });
}

#[test]
fn multiple_monthly_releases_work() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let monthly_amount = PezTreasury::halving_info().monthly_amount;

        // Release month 0
        run_to_block(432_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        assert_eq!(PezTreasury::next_release_month(), 1);

        // Release month 1
        run_to_block(864_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        assert_eq!(PezTreasury::next_release_month(), 2);

        // Release month 2
        run_to_block(1_296_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        assert_eq!(PezTreasury::next_release_month(), 3);

        // Verify total released
        let halving_info = PezTreasury::halving_info();
        assert_eq!(halving_info.total_released, monthly_amount * 3);
    });
}

// =============================================================================
// 4. HALVING LOGIC TESTS
// =============================================================================

#[test]
fn halving_occurs_after_48_months() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let initial_monthly = PezTreasury::halving_info().monthly_amount;

        // Release 47 months (no halving yet)
        for month in 0..47 {
            run_to_block(1 + (month + 1) * 432_000 + 1);
            assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        }

        // Still period 0
        assert_eq!(PezTreasury::halving_info().current_period, 0);
        assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly);

        // Release 48th month - halving should occur
        run_to_block(1 + 48 * 432_000 + 1);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        // Now in period 1 with halved amount
        let halving_info = PezTreasury::halving_info();
        assert_eq!(halving_info.current_period, 1);
        assert_eq!(halving_info.monthly_amount, initial_monthly / 2);

        // Verify event
        System::assert_has_event(
            Event::NewHalvingPeriod {
                period: 1,
                new_monthly_amount: initial_monthly / 2,
            }
            .into(),
        );
    });
}

#[test]
fn multiple_halvings_work() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let initial_monthly = PezTreasury::halving_info().monthly_amount;

        // First halving at month 48
        run_to_block(1 + 48 * 432_000 + 1);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        assert_eq!(PezTreasury::halving_info().current_period, 1);
        assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly / 2);

        // Second halving at month 96
        run_to_block(1 + 96 * 432_000 + 1);
        for _ in 49..=96 {
            assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        }
        assert_eq!(PezTreasury::halving_info().current_period, 2);
        assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly / 4);

        // Third halving at month 144
        run_to_block(1 + 144 * 432_000 + 1);
        for _ in 97..=144 {
            assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        }
        assert_eq!(PezTreasury::halving_info().current_period, 3);
        assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly / 8);
    });
}

#[test]
fn halving_period_start_block_updates() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let period_0_start = PezTreasury::halving_info().period_start_block;

        // Trigger halving
        run_to_block(1 + 48 * 432_000 + 1);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        let period_1_start = PezTreasury::halving_info().period_start_block;
        assert!(period_1_start > period_0_start);
        assert_eq!(period_1_start, System::block_number());
    });
}

// =============================================================================
// 5. ERROR CASES
// =============================================================================

#[test]
fn insufficient_treasury_balance_error() {
    new_test_ext().execute_with(|| {
        // Initialize without genesis distribution (treasury empty)
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        run_to_block(432_001);

        // This should fail due to insufficient balance
        assert_noop!(
            PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
            Error::<Test>::InsufficientTreasuryBalance
        );
    });
}

#[test]
fn release_requires_root_origin() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        run_to_block(432_001);

        assert_noop!(
            PezTreasury::release_monthly_funds(RuntimeOrigin::signed(alice())),
            sp_runtime::DispatchError::BadOrigin
        );
    });
}

// =============================================================================
// 6. EDGE CASES
// =============================================================================

#[test]
fn release_exactly_at_boundary_block_fails() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        // Tam 432_000. blok (start_block=1 olduğu için) 431_999 blok geçti demektir.
        // Bu, 1 tam ay (432_000 blok) değildir.
        run_to_block(432_000);
        assert_noop!(
            PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
            Error::<Test>::ReleaseTooEarly
        );
    });
}

#[test]
fn release_one_block_before_boundary_fails() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        run_to_block(432_000 - 1);
        assert_noop!(
            PezTreasury::release_monthly_funds(RuntimeOrigin::root()),
            Error::<Test>::ReleaseTooEarly
        );
    });
}

#[test]
fn skip_months_and_release() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        // Skip directly to month 3
        run_to_block(1 + 3 * 432_000 + 1);

        // Should release month 0
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        assert_eq!(PezTreasury::next_release_month(), 1);

        // Can still release subsequent months
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        assert_eq!(PezTreasury::next_release_month(), 2);
    });
}

#[test]
fn very_large_block_number() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        // Jump to very large block number
        System::set_block_number(u64::MAX / 2);

        // Should still be able to release (if months passed)
        // This tests overflow protection
        let result = PezTreasury::release_monthly_funds(RuntimeOrigin::root());
        // Result depends on whether enough months passed
        // Main point: no panic/overflow
        assert!(result.is_ok() || result.is_err());
    });
}

#[test]
fn zero_amount_division_protection() {
    new_test_ext().execute_with(|| {
        // Initialize without any balance
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let halving_info = PezTreasury::halving_info();
        // Should not panic, should have some calculated amount
        assert!(!halving_info.monthly_amount.is_zero());
    });
}

// =============================================================================
// 7. GETTER FUNCTIONS TESTS
// =============================================================================

#[test]
fn get_current_halving_info_works() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let info = PezTreasury::get_current_halving_info();
        assert_eq!(info.current_period, 0);
        assert!(!info.monthly_amount.is_zero());
        assert_eq!(info.total_released, 0);
    });
}

#[test]
fn get_incentive_pot_balance_works() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        run_to_block(432_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        let balance = PezTreasury::get_incentive_pot_balance();
        assert!(balance > 0);
    });
}

#[test]
fn get_government_pot_balance_works() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        run_to_block(432_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        let balance = PezTreasury::get_government_pot_balance();
        assert!(balance > 0);
    });
}

// =============================================================================
// 8. ACCOUNT ID TESTS
// =============================================================================

#[test]
fn treasury_account_id_is_consistent() {
    new_test_ext().execute_with(|| {
        let account1 = PezTreasury::treasury_account_id();
        let account2 = PezTreasury::treasury_account_id();
        assert_eq!(account1, account2);
    });
}

#[test]
fn pot_accounts_are_different() {
    new_test_ext().execute_with(|| {
        debug_pot_accounts();
        
        let treasury = PezTreasury::treasury_account_id();
        let incentive = PezTreasury::incentive_pot_account_id();
        let government = PezTreasury::government_pot_account_id();

        println!("\n=== Account IDs from Pallet ===");
        println!("Treasury: {:?}", treasury);
        println!("Incentive: {:?}", incentive);
        println!("Government: {:?}", government);
        println!("================================\n");

        // Tüm üçü farklı olmalı
        assert_ne!(treasury, incentive, "Treasury and Incentive must be different");
        assert_ne!(treasury, government, "Treasury and Government must be different");
        assert_ne!(incentive, government, "Incentive and Government must be different");

        println!("✓ All pot accounts are different!");
    });
}

// =============================================================================
// 9. MONTHLY RELEASE STORAGE TESTS
// =============================================================================

#[test]
fn monthly_release_records_stored_correctly() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let monthly_amount = PezTreasury::halving_info().monthly_amount;
        let incentive_expected = monthly_amount * 75 / 100;
        let government_expected = monthly_amount - incentive_expected;

        run_to_block(432_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        // Verify monthly release record
        let release = PezTreasury::monthly_releases(0).unwrap();
        assert_eq!(release.month_index, 0);
        assert_eq!(release.amount_released, monthly_amount);
        assert_eq!(release.incentive_amount, incentive_expected);
        assert_eq!(release.government_amount, government_expected);
        assert_eq!(release.release_block, System::block_number());
    });
}

#[test]
fn multiple_monthly_releases_stored_separately() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        // Release month 0
        run_to_block(432_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        // Release month 1
        run_to_block(864_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        // Verify both records exist
        assert!(PezTreasury::monthly_releases(0).is_some());
        assert!(PezTreasury::monthly_releases(1).is_some());

        let release_0 = PezTreasury::monthly_releases(0).unwrap();
        let release_1 = PezTreasury::monthly_releases(1).unwrap();

        assert_eq!(release_0.month_index, 0);
        assert_eq!(release_1.month_index, 1);
        assert_ne!(release_0.release_block, release_1.release_block);
    });
}

// =============================================================================
// 10. INTEGRATION TESTS
// =============================================================================

#[test]
fn full_lifecycle_test() {
    new_test_ext().execute_with(|| {
        // 1. Genesis distribution
        assert_ok!(PezTreasury::do_genesis_distribution());
        let treasury_initial = Assets::balance(PezAssetId::get(), treasury_account());
        assert!(treasury_initial > 0);

        // 2. Initialize treasury
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
        let monthly_amount = PezTreasury::halving_info().monthly_amount;

        // 3. Release first month
        run_to_block(432_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        
        let treasury_after_month_0 = Assets::balance(PezAssetId::get(), treasury_account());
        assert_eq!(treasury_initial - treasury_after_month_0, monthly_amount);

        // 4. Release multiple months
        for month in 1..10 {
            run_to_block(1 + (month + 1) * 432_000 + 1);
            assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        }

        // 5. Verify cumulative release
        let halving_info = PezTreasury::halving_info();
        assert_eq!(halving_info.total_released, monthly_amount * 10);

        // 6. Verify treasury balance decreased correctly
        let treasury_after_10_months = Assets::balance(PezAssetId::get(), treasury_account());
        assert_eq!(
            treasury_initial - treasury_after_10_months,
            monthly_amount * 10
        );
    });
}

#[test]
fn full_halving_cycle_test() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let initial_monthly = PezTreasury::halving_info().monthly_amount;
        let mut cumulative_released = 0u128;

        // Period 0: 48 months at initial rate
		for month in 0..48 {
			run_to_block(1 + (month + 1) * 432_000 + 1);
			assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

			if month < 47 {
				cumulative_released += initial_monthly;
			} else {
				// 48. sürümde (index 47) halving tetiklenir ve yarı tutar kullanılır
				cumulative_released += initial_monthly / 2;
			}
		}

        assert_eq!(PezTreasury::halving_info().current_period, 1);
        assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly / 2);

        // Period 1: 48 months at half rate
		for month in 48..96 {
			run_to_block(1 + (month + 1) * 432_000 + 1);
			assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

			if month < 95 {
				cumulative_released += initial_monthly / 2;
			} else {
				// 96. sürümde (index 95) ikinci halving tetiklenir
				cumulative_released += initial_monthly / 4;
			}
		}

        assert_eq!(PezTreasury::halving_info().current_period, 2);
        assert_eq!(PezTreasury::halving_info().monthly_amount, initial_monthly / 4);

        // Verify total released matches expectation
        assert_eq!(
            PezTreasury::halving_info().total_released,
            cumulative_released
        );
    });
}

// =============================================================================
// 11. PRECISION AND ROUNDING TESTS
// =============================================================================

#[test]
fn division_rounding_is_consistent() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let monthly_amount = PezTreasury::halving_info().monthly_amount;
        let incentive_amount = monthly_amount * 75 / 100;
        let government_amount = monthly_amount - incentive_amount;

        // Verify no rounding loss
        assert_eq!(incentive_amount + government_amount, monthly_amount);
    });
}

#[test]
fn halving_precision_maintained() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let initial = PezTreasury::halving_info().monthly_amount;

        // Trigger halving
        run_to_block(1 + 48 * 432_000 + 1);
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        let after_halving = PezTreasury::halving_info().monthly_amount;

        // Check halving is exactly half (no precision loss)
        assert_eq!(after_halving, initial / 2);
    });
}

// =============================================================================
// 12. EVENT EMISSION TESTS
// =============================================================================

#[test]
fn all_events_emitted_correctly() {
    new_test_ext().execute_with(|| {
        // Genesis distribution event
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert!(System::events().iter().any(|e| matches!(
            e.event,
            RuntimeEvent::PezTreasury(Event::GenesisDistributionCompleted { .. })
        )));

        // Treasury initialized event
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
        assert!(System::events().iter().any(|e| matches!(
            e.event,
            RuntimeEvent::PezTreasury(Event::TreasuryInitialized { .. })
        )));

        // Monthly funds released event
        run_to_block(432_001);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        assert!(System::events().iter().any(|e| matches!(
            e.event,
            RuntimeEvent::PezTreasury(Event::MonthlyFundsReleased { .. })
        )));
    });
}

#[test]
fn halving_event_emitted_at_correct_time() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        // Clear existing events
        System::reset_events();

        // Release up to halving point
        run_to_block(1 + 48 * 432_000 + 1);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        // Verify halving event emitted
        assert!(System::events().iter().any(|e| matches!(
            e.event,
            RuntimeEvent::PezTreasury(Event::NewHalvingPeriod { period: 1, .. })
        )));
    });
}

// =============================================================================
// 13. STRESS TESTS
// =============================================================================

#[test]
fn many_consecutive_releases() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        // Release 100 months consecutively
        for month in 0..100 {
            run_to_block(1 + (month + 1) * 432_000 + 1);
            assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));
        }

        // Verify state is consistent
        assert_eq!(PezTreasury::next_release_month(), 100);
        
        // Should be in period 2 (after 2 halvings at months 48 and 96)
        assert_eq!(PezTreasury::halving_info().current_period, 2);
    });
}

#[test]
fn treasury_never_goes_negative() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let _initial_balance = Assets::balance(PezAssetId::get(), treasury_account()); // FIXED: Prefixed with underscore
        
        // Try to release many months
        for month in 0..200 {
            run_to_block(1 + (month + 1) * 432_000 + 1);
            
            let before_balance = Assets::balance(PezAssetId::get(), treasury_account());
            
            let result = PezTreasury::release_monthly_funds(RuntimeOrigin::root());
            
            if result.is_ok() {
                let after_balance = Assets::balance(PezAssetId::get(), treasury_account());
                // Balance should decrease or stay the same, never increase
                assert!(after_balance <= before_balance);
                // Balance should never go below zero
                assert!(after_balance >= 0);
            } else {
                // If release fails, balance should be unchanged
                assert_eq!(
                    before_balance,
                    Assets::balance(PezAssetId::get(), treasury_account())
                );
                break;
            }
        }
    });
}

// =============================================================================
// 14. BOUNDARY CONDITION TESTS
// =============================================================================

#[test]
fn first_block_initialization() {
    new_test_ext().execute_with(|| {
        System::set_block_number(1);
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));
        assert_eq!(PezTreasury::treasury_start_block(), Some(1));
    });
}

#[test]
fn last_month_of_period_before_halving() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let initial_amount = PezTreasury::halving_info().monthly_amount;

        // Release month 47 (last before halving)
        run_to_block(1 + 47 * 432_000 + 1);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        // Should still be in period 0
        assert_eq!(PezTreasury::halving_info().current_period, 0);
        assert_eq!(PezTreasury::halving_info().monthly_amount, initial_amount);
    });
}

#[test]
fn first_month_after_halving() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let initial_amount = PezTreasury::halving_info().monthly_amount;

        // Trigger halving at month 48
        run_to_block(1 + 48 * 432_000 + 1);
        assert_ok!(PezTreasury::release_monthly_funds(RuntimeOrigin::root()));

        // Should be in period 1 with halved amount
        assert_eq!(PezTreasury::halving_info().current_period, 1);
        assert_eq!(PezTreasury::halving_info().monthly_amount, initial_amount / 2);
    });
}

// =============================================================================
// 15. MATHEMATICAL CORRECTNESS TESTS
// =============================================================================

#[test]
fn total_supply_equals_sum_of_allocations() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());

        let treasury = Assets::balance(PezAssetId::get(), treasury_account());
        let presale_acc = Assets::balance(PezAssetId::get(), presale());
        let founder_acc = Assets::balance(PezAssetId::get(), founder());

        let total = treasury + presale_acc + founder_acc;
        let expected_total = 5_000_000_000 * 1_000_000_000_000u128;

        assert_eq!(total, expected_total);
    });
}

#[test]
fn percentage_allocations_correct() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());

        let total_supply = 5_000_000_000 * 1_000_000_000_000u128;
        let treasury = Assets::balance(PezAssetId::get(), treasury_account());
        let presale_acc = Assets::balance(PezAssetId::get(), presale());
        let founder_acc = Assets::balance(PezAssetId::get(), founder());

        assert_eq!(treasury, total_supply * 9625 / 10000);
        assert_eq!(presale_acc, total_supply * 1875 / 100000);
        assert_eq!(founder_acc, total_supply * 1875 / 100000);
    });
}

#[test]
fn first_period_total_is_half_of_treasury() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::do_genesis_distribution());
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let monthly_amount = PezTreasury::halving_info().monthly_amount;
        let first_period_total = monthly_amount * 48;

        let treasury_allocation = 4_812_500_000 * 1_000_000_000_000u128;
        let expected_first_period = treasury_allocation / 2;

        let diff = expected_first_period.saturating_sub(first_period_total);
		// Kalanların toplamı 48'den az olmalı (her ay en fazla 1 birim kalan)
		assert!(diff < 48, "Rounding error too large: {}", diff);
    });
}

#[test]
fn geometric_series_sum_validates() {
    new_test_ext().execute_with(|| {
        assert_ok!(PezTreasury::initialize_treasury(RuntimeOrigin::root()));

        let initial_monthly = PezTreasury::halving_info().monthly_amount;
        
        // Sum of geometric series: a(1 - r^n) / (1 - r)
        // For halving: first_period * (1 - 0.5^n) / 0.5
        // With infinite halvings approaches: first_period * 2
        
        let first_period_total = initial_monthly * 48;
        let treasury_allocation = 4_812_500_000 * 1_000_000_000_000u128;
        
        // After infinite halvings, total distributed = treasury_allocation
        // first_period_total * 2 = treasury_allocation
        let diff = treasury_allocation.saturating_sub(first_period_total * 2);
		// Kalanların toplamı (2 ile çarpılmış) 96'dan az olmalı
		assert!(diff < 96, "Rounding error too large: {}", diff);
    });
}