// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.19;

import "../src/VWAPTracker.sol";
import "./mocks/MockVWAPTracker.sol";
import "forge-std/Test.sol";

/**
 * @title VWAPTracker Test Suite
 * @notice Comprehensive tests for the VWAPTracker contract including:
 *         - Basic VWAP calculation functionality
 *         - Overflow handling in cumulative calculations
 *         - Adjusted VWAP with capital inefficiency
 *         - Volume weighted price accumulation
 */
contract VWAPTrackerTest is Test {
    MockVWAPTracker vwapTracker;

    // Test constants
    uint256 constant SAMPLE_PRICE_X96 = 79_228_162_514_264_337_593_543_950_336; // 1.0 in X96 format
    uint256 constant SAMPLE_FEE = 1 ether;
    uint256 constant CAPITAL_INEFFICIENCY = 5 * 10 ** 17; // 50%

    function setUp() public {
        vwapTracker = new MockVWAPTracker();
    }

    // ========================================
    // BASIC VWAP FUNCTIONALITY TESTS
    // ========================================

    function testInitialState() public {
        assertEq(vwapTracker.cumulativeVolumeWeightedPriceX96(), 0, "Initial cumulative VWAP should be zero");
        assertEq(vwapTracker.cumulativeVolume(), 0, "Initial cumulative volume should be zero");
        assertEq(vwapTracker.getVWAP(), 0, "Initial VWAP should be zero");
        assertEq(vwapTracker.getAdjustedVWAP(CAPITAL_INEFFICIENCY), 0, "Initial adjusted VWAP should be zero");
    }

    function testSinglePriceRecording() public {
        vwapTracker.recordVolumeAndPrice(SAMPLE_PRICE_X96, SAMPLE_FEE);

        uint256 expectedVolume = SAMPLE_FEE * 100; // Fee is 1% of volume
        uint256 expectedVWAP = SAMPLE_PRICE_X96;

        assertEq(vwapTracker.cumulativeVolume(), expectedVolume, "Volume should be recorded correctly");
        assertEq(vwapTracker.getVWAP(), expectedVWAP, "VWAP should equal the single price");

        uint256 adjustedVWAP = vwapTracker.getAdjustedVWAP(CAPITAL_INEFFICIENCY);
        uint256 expectedAdjustedVWAP = (7 * expectedVWAP / 10) + (expectedVWAP * CAPITAL_INEFFICIENCY / 10 ** 18);
        assertEq(adjustedVWAP, expectedAdjustedVWAP, "Adjusted VWAP should be calculated correctly");
    }

    function testMultiplePriceRecording() public {
        // Record first price
        uint256 price1 = SAMPLE_PRICE_X96;
        uint256 fee1 = 1 ether;
        vwapTracker.recordVolumeAndPrice(price1, fee1);

        // Record second price (double the first)
        uint256 price2 = SAMPLE_PRICE_X96 * 2;
        uint256 fee2 = 2 ether;
        vwapTracker.recordVolumeAndPrice(price2, fee2);

        uint256 volume1 = fee1 * 100;
        uint256 volume2 = fee2 * 100;
        uint256 expectedTotalVolume = volume1 + volume2;

        uint256 expectedVWAP = (price1 * volume1 + price2 * volume2) / expectedTotalVolume;

        assertEq(vwapTracker.cumulativeVolume(), expectedTotalVolume, "Total volume should be sum of individual volumes");
        assertEq(vwapTracker.getVWAP(), expectedVWAP, "VWAP should be correctly weighted average");
    }

    function testVWAPReset() public {
        vwapTracker.recordVolumeAndPrice(SAMPLE_PRICE_X96, SAMPLE_FEE);

        assertGt(vwapTracker.getVWAP(), 0, "VWAP should be non-zero after recording");

        vwapTracker.resetVWAP();

        assertEq(vwapTracker.cumulativeVolumeWeightedPriceX96(), 0, "Cumulative VWAP should be reset to zero");
        assertEq(vwapTracker.cumulativeVolume(), 0, "Cumulative volume should be reset to zero");
        assertEq(vwapTracker.getVWAP(), 0, "VWAP should be zero after reset");
    }

    // ========================================
    // OVERFLOW HANDLING TESTS
    // ========================================

    function testOverflowHandling() public {
        // Set cumulative values to near overflow
        vm.store(
            address(vwapTracker),
            bytes32(uint256(0)), // cumulativeVolumeWeightedPriceX96 storage slot
            bytes32(uint256(10 ** 70 + 1))
        );

        vm.store(
            address(vwapTracker),
            bytes32(uint256(1)), // cumulativeVolume storage slot
            bytes32(uint256(10 ** 40))
        );

        uint256 beforeVWAP = vwapTracker.cumulativeVolumeWeightedPriceX96();
        uint256 beforeVolume = vwapTracker.cumulativeVolume();

        assertGt(beforeVWAP, 10 ** 70, "Initial cumulative VWAP should be above overflow threshold");

        // Record a price that should trigger overflow handling
        vwapTracker.recordVolumeAndPrice(SAMPLE_PRICE_X96, SAMPLE_FEE);

        uint256 afterVWAP = vwapTracker.cumulativeVolumeWeightedPriceX96();
        uint256 afterVolume = vwapTracker.cumulativeVolume();

        // Values should be compressed (smaller than before)
        assertLt(afterVWAP, beforeVWAP, "VWAP should be compressed after overflow");
        assertLt(afterVolume, beforeVolume, "Volume should be compressed after overflow");

        // But still maintain reasonable ratio
        uint256 calculatedVWAP = afterVWAP / afterVolume;
        assertGt(calculatedVWAP, 0, "Calculated VWAP should be positive after overflow handling");
        assertLt(calculatedVWAP, 10 ** 40, "Calculated VWAP should be within reasonable bounds");
    }

    function testOverflowCompressionRatio() public {
        // Test that compression preserves historical significance (eternal memory for dormant whale protection)
        uint256 initialVWAP = 10 ** 70 + 1;
        uint256 initialVolume = 10 ** 40;

        vm.store(address(vwapTracker), bytes32(uint256(0)), bytes32(initialVWAP));
        vm.store(address(vwapTracker), bytes32(uint256(1)), bytes32(initialVolume));

        uint256 expectedRatioBefore = initialVWAP / initialVolume; // ≈ 10^30

        vwapTracker.recordVolumeAndPrice(SAMPLE_PRICE_X96, SAMPLE_FEE);

        uint256 finalVWAP = vwapTracker.cumulativeVolumeWeightedPriceX96();
        uint256 finalVolume = vwapTracker.cumulativeVolume();
        uint256 actualRatio = finalVWAP / finalVolume;

        // CRITICAL: The fixed compression algorithm should preserve historical significance
        // Maximum compression factor is 1000x, so historical data should still dominate
        // This is essential for dormant whale protection - historical prices must retain weight

        assertGt(actualRatio, 0, "Compression should maintain positive ratio");

        // Historical data should still dominate after compression (not the new price)
        // With 1000x max compression, historical ratio should be preserved within reasonable bounds
        uint256 tolerance = expectedRatioBefore / 2; // 50% tolerance for new data influence
        assertGt(actualRatio, expectedRatioBefore - tolerance, "Historical data should still dominate after compression");
        assertLt(actualRatio, expectedRatioBefore + tolerance, "Historical data should still dominate after compression");

        // Verify the ratio is NOT close to the new price (which would indicate broken dormant whale protection)
        uint256 newPriceRatio = SAMPLE_PRICE_X96; // ≈ 7.9 * 10^28, much smaller than historical ratio
        assertGt(actualRatio, newPriceRatio * 2, "VWAP should not be dominated by new price - dormant whale protection");
    }

    function testDormantWhaleProtection() public {
        // Test that VWAP maintains historical memory to prevent dormant whale attacks

        // Phase 1: Establish historical low prices with significant volume
        uint256 cheapPrice = SAMPLE_PRICE_X96 / 10; // 10x cheaper than sample
        uint256 historicalVolume = 100 ether; // Large volume to establish strong historical weight

        // Build up significant historical data at cheap prices
        for (uint256 i = 0; i < 10; i++) {
            vwapTracker.recordVolumeAndPrice(cheapPrice, historicalVolume);
        }

        uint256 earlyVWAP = vwapTracker.getVWAP();
        assertEq(earlyVWAP, cheapPrice, "Early VWAP should equal the cheap price");

        // Phase 2: Simulate large historical data that maintains the cheap price ratio
        // Set values that will trigger compression while preserving the cheap price VWAP
        uint256 historicalVWAPValue = 10 ** 70 + 1; // Trigger compression threshold
        uint256 adjustedVolume = historicalVWAPValue / cheapPrice; // Maintain cheap price ratio

        vm.store(address(vwapTracker), bytes32(uint256(0)), bytes32(historicalVWAPValue));
        vm.store(address(vwapTracker), bytes32(uint256(1)), bytes32(adjustedVolume));

        // Verify historical cheap price is preserved
        uint256 preWhaleVWAP = vwapTracker.getVWAP();
        assertApproxEqRel(preWhaleVWAP, cheapPrice, 0.01e18, "Historical cheap price should be preserved"); // 1% tolerance

        // Phase 3: Whale tries to sell at high price (this should trigger compression)
        uint256 expensivePrice = SAMPLE_PRICE_X96 * 10; // 10x more expensive
        uint256 whaleVolume = 10 ether; // Whale's volume
        vwapTracker.recordVolumeAndPrice(expensivePrice, whaleVolume);

        uint256 finalVWAP = vwapTracker.getVWAP();

        // CRITICAL: Final VWAP should still be much closer to historical cheap price
        // Even after compression, historical data should provide protection
        assertLt(finalVWAP, cheapPrice * 2, "VWAP should remain close to historical prices despite expensive whale trade");

        // The whale's expensive price should not dominate the VWAP
        uint256 whaleInfluenceRatio = (finalVWAP * 100) / cheapPrice; // How much did whale inflate the price?
        assertLt(whaleInfluenceRatio, 300, "Whale should not be able to inflate VWAP by more than 3x from historical levels");

        console.log("Historical cheap price:", cheapPrice);
        console.log("Whale expensive price:", expensivePrice);
        console.log("Final VWAP:", finalVWAP);
        console.log("VWAP inflation from whale:", whaleInfluenceRatio, "% (should be limited)");
    }

    // ========================================
    // ADJUSTED VWAP TESTS
    // ========================================

    function testAdjustedVWAPCalculation() public {
        vwapTracker.recordVolumeAndPrice(SAMPLE_PRICE_X96, SAMPLE_FEE);

        uint256 baseVWAP = vwapTracker.getVWAP();
        uint256 adjustedVWAP = vwapTracker.getAdjustedVWAP(CAPITAL_INEFFICIENCY);

        uint256 expectedAdjustedVWAP = (7 * baseVWAP / 10) + (baseVWAP * CAPITAL_INEFFICIENCY / 10 ** 18);

        assertEq(adjustedVWAP, expectedAdjustedVWAP, "Adjusted VWAP should match expected calculation");
        // With 50% capital inefficiency: 70% + 50% = 120% of base VWAP
        assertGt(adjustedVWAP, baseVWAP, "Adjusted VWAP should be greater than base VWAP with 50% capital inefficiency");
    }

    function testAdjustedVWAPWithZeroCapitalInefficiency() public {
        vwapTracker.recordVolumeAndPrice(SAMPLE_PRICE_X96, SAMPLE_FEE);

        uint256 baseVWAP = vwapTracker.getVWAP();
        uint256 adjustedVWAP = vwapTracker.getAdjustedVWAP(0);

        uint256 expectedAdjustedVWAP = 7 * baseVWAP / 10;

        assertEq(adjustedVWAP, expectedAdjustedVWAP, "Adjusted VWAP with zero capital inefficiency should be 70% of base");
    }

    function testAdjustedVWAPWithMaxCapitalInefficiency() public {
        vwapTracker.recordVolumeAndPrice(SAMPLE_PRICE_X96, SAMPLE_FEE);

        uint256 baseVWAP = vwapTracker.getVWAP();
        uint256 adjustedVWAP = vwapTracker.getAdjustedVWAP(10 ** 18); // 100% capital inefficiency

        uint256 expectedAdjustedVWAP = (7 * baseVWAP / 10) + baseVWAP;

        assertEq(adjustedVWAP, expectedAdjustedVWAP, "Adjusted VWAP with max capital inefficiency should be 170% of base");
    }

    // ========================================
    // FUZZ TESTS
    // ========================================

    function testFuzzVWAPCalculation(uint256 price, uint256 fee) public {
        // Bound inputs to reasonable ranges
        price = bound(price, 1000, type(uint128).max);
        fee = bound(fee, 1000, type(uint64).max);

        vwapTracker.recordVolumeAndPrice(price, fee);

        uint256 expectedVolume = fee * 100;
        uint256 expectedVWAP = price;

        assertEq(vwapTracker.cumulativeVolume(), expectedVolume, "Volume should be recorded correctly");
        assertEq(vwapTracker.getVWAP(), expectedVWAP, "VWAP should equal the single price");

        // Test that adjusted VWAP is within reasonable bounds
        uint256 adjustedVWAP = vwapTracker.getAdjustedVWAP(CAPITAL_INEFFICIENCY);
        assertGt(adjustedVWAP, 0, "Adjusted VWAP should be positive");
        assertLt(adjustedVWAP, price * 2, "Adjusted VWAP should be less than twice the base price");
    }

    function testConcreteMultipleRecordings() public {
        // Test with concrete values to ensure deterministic behavior
        uint256[] memory prices = new uint256[](3);
        uint256[] memory fees = new uint256[](3);

        prices[0] = 100_000;
        prices[1] = 200_000;
        prices[2] = 150_000;

        fees[0] = 1000;
        fees[1] = 2000;
        fees[2] = 1500;

        uint256 totalVWAP = 0;
        uint256 totalVolume = 0;

        for (uint256 i = 0; i < prices.length; i++) {
            uint256 volume = fees[i] * 100;
            totalVWAP += prices[i] * volume;
            totalVolume += volume;

            vwapTracker.recordVolumeAndPrice(prices[i], fees[i]);
        }

        uint256 expectedVWAP = totalVWAP / totalVolume;
        uint256 actualVWAP = vwapTracker.getVWAP();

        assertEq(actualVWAP, expectedVWAP, "VWAP should be correctly calculated across multiple recordings");
        assertEq(vwapTracker.cumulativeVolume(), totalVolume, "Total volume should be sum of all volumes");
    }

    // ========================================
    // EDGE CASE TESTS
    // ========================================

    function testZeroVolumeHandling() public {
        // Don't record any prices
        assertEq(vwapTracker.getVWAP(), 0, "VWAP should be zero with no volume");
        assertEq(vwapTracker.getAdjustedVWAP(CAPITAL_INEFFICIENCY), 0, "Adjusted VWAP should be zero with no volume");
    }

    function testMinimalValues() public {
        // Test with minimal non-zero values
        vwapTracker.recordVolumeAndPrice(1, 1);

        uint256 expectedVolume = 100; // 1 * 100
        uint256 expectedVWAP = 1;

        assertEq(vwapTracker.cumulativeVolume(), expectedVolume, "Volume should handle minimal values");
        assertEq(vwapTracker.getVWAP(), expectedVWAP, "VWAP should handle minimal values");
    }

    function testLargeButSafeValues() public {
        // Test with large but safe values (below overflow threshold)
        uint256 largePrice = type(uint128).max;
        uint256 largeFee = type(uint64).max;

        vwapTracker.recordVolumeAndPrice(largePrice, largeFee);

        uint256 expectedVolume = largeFee * 100;
        uint256 expectedVWAP = largePrice;

        assertEq(vwapTracker.cumulativeVolume(), expectedVolume, "Volume should handle large values");
        assertEq(vwapTracker.getVWAP(), expectedVWAP, "VWAP should handle large values");
    }

    // ========================================
    // DOUBLE OVERFLOW PROTECTION TESTS
    // ========================================

    /**
     * @notice Test double overflow protection under extreme ETH price scenario
     * @dev Simulates ETH at $1M, HARB at $1 - validates that unrealistic fees are required for double overflow
     */
    function testDoubleOverflowExtremeEthPriceScenario() public {
        // Set up post-compression state (simulate 1000x compression already occurred)
        uint256 maxSafeValue = type(uint256).max / 10 ** 6; // Compression trigger point
        uint256 compressedValue = maxSafeValue; // Near threshold after compression

        // Manually set post-compression state
        vm.store(address(vwapTracker), bytes32(uint256(0)), bytes32(compressedValue));
        vm.store(address(vwapTracker), bytes32(uint256(1)), bytes32(compressedValue / (10 ** 30)));

        // Calculate space available before next overflow
        uint256 availableSpace = type(uint256).max - compressedValue;
        uint256 minProductForOverflow = availableSpace / 100 + 1; // price * fee * 100 > availableSpace

        // Extreme ETH price scenario: ETH = $1M, HARB = $1
        uint256 extremeEthPriceUSD = 1_000_000;
        uint256 harbPriceUSD = 1;
        uint256 realisticPriceX96 = (uint256(harbPriceUSD) << 96) / extremeEthPriceUSD;

        // Calculate required fee for double overflow
        uint256 requiredFee = minProductForOverflow / realisticPriceX96;

        // ASSERTIONS: Verify double overflow requires unrealistic conditions
        assertGt(requiredFee, 1000 ether, "Double overflow requires unrealistic fee > 1000 ETH");
        assertGt(requiredFee * extremeEthPriceUSD / 10 ** 18, 1_000_000_000, "Required fee exceeds $1B USD");

        // Verify the mathematical relationship
        assertEq(minProductForOverflow, availableSpace / 100 + 1, "Overflow threshold calculation correct");

        // Verify compression provides adequate protection
        assertGt(minProductForOverflow, 10 ** 50, "Product threshold astronomically high");
    }

    /**
     * @notice Test double overflow protection under hyperinflated HARB price scenario
     * @dev Simulates HARB at $1M, ETH at $3k - validates that unrealistic fees are required for double overflow
     */
    function testDoubleOverflowHyperinflatedHarbScenario() public {
        // Set up post-compression state (simulate 1000x compression already occurred)
        uint256 maxSafeValue = type(uint256).max / 10 ** 6;
        uint256 compressedValue = maxSafeValue;

        // Manually set post-compression state
        vm.store(address(vwapTracker), bytes32(uint256(0)), bytes32(compressedValue));
        vm.store(address(vwapTracker), bytes32(uint256(1)), bytes32(compressedValue / (10 ** 30)));

        // Calculate overflow requirements
        uint256 availableSpace = type(uint256).max - compressedValue;
        uint256 minProductForOverflow = availableSpace / 100 + 1;

        // Hyperinflated HARB scenario: HARB = $1M, ETH = $3k
        uint256 normalEthPrice = 3000;
        uint256 hyperInflatedHarbPrice = 1_000_000;
        uint256 hyperInflatedPriceX96 = (uint256(hyperInflatedHarbPrice) << 96) / normalEthPrice;

        // Calculate required fee for double overflow
        uint256 requiredFee = minProductForOverflow / hyperInflatedPriceX96;

        // ASSERTIONS: Verify double overflow requires unrealistic conditions
        assertGt(requiredFee, 100 ether, "Double overflow requires unrealistic fee > 100 ETH");
        assertGt(requiredFee * normalEthPrice / 10 ** 18, 300_000, "Required fee exceeds $300k USD");

        // Verify HARB price assumption is unrealistic
        assertGt(hyperInflatedHarbPrice, 100_000, "HARB price > $100k is unrealistic");

        // Verify overflow protection holds
        assertGt(minProductForOverflow, 10 ** 50, "Product threshold astronomically high");
    }

    /**
     * @notice Test double overflow protection under maximum transaction scenario
     * @dev Simulates maximum reasonable transaction size - validates required token prices are unrealistic
     */
    function testDoubleOverflowMaximumTransactionScenario() public {
        // Set up post-compression state (simulate 1000x compression already occurred)
        uint256 maxSafeValue = type(uint256).max / 10 ** 6;
        uint256 compressedValue = maxSafeValue;

        // Manually set post-compression state
        vm.store(address(vwapTracker), bytes32(uint256(0)), bytes32(compressedValue));
        vm.store(address(vwapTracker), bytes32(uint256(1)), bytes32(compressedValue / (10 ** 30)));

        // Calculate overflow requirements
        uint256 availableSpace = type(uint256).max - compressedValue;
        uint256 minProductForOverflow = availableSpace / 100 + 1;

        // Maximum reasonable transaction scenario: 10,000 ETH (unrealistically large)
        uint256 maxReasonableFee = 10_000 ether;
        uint256 minPriceForOverflow = minProductForOverflow / maxReasonableFee;

        // Convert to USD equivalent (assuming $3k ETH)
        uint256 minHarbPriceInEth = minPriceForOverflow >> 96;
        uint256 minHarbPriceUSD = minHarbPriceInEth * 3000;

        // ASSERTIONS: Verify double overflow requires unrealistic token prices
        assertGt(minHarbPriceUSD, 1_000_000_000, "Required HARB price > $1B (exceeds global wealth)");
        assertGt(minPriceForOverflow, 10 ** 30, "Required price X96 astronomically high");

        // Verify transaction size assumption is already unrealistic
        assertGt(maxReasonableFee, 1000 ether, "10k ETH transaction is unrealistic");

        // Verify the 1000x compression limit provides adequate protection
        assertGt(minProductForOverflow, 10 ** 50, "Product threshold provides adequate protection");

        // Verify mathematical consistency
        assertEq(minPriceForOverflow, minProductForOverflow / maxReasonableFee, "Price calculation correct");
    }

    // ========================================
    // SINGLE-TRANSACTION OVERFLOW PROTECTION
    // ========================================

    /**
     * @notice Test the ultra-rare single-transaction overflow protection (lines 36-41 of VWAPTracker)
     * @dev Uses a price so large that price * volume exceeds type(uint256).max / 2 without
     *      itself overflowing uint256. This exercises the cap-and-recalculate branch.
     */
    function testSingleTransactionOverflowProtection() public {
        // Choose price such that price * (fee * 100) > type(uint256).max / 2
        // but the multiplication itself does NOT overflow uint256.
        //
        // price = type(uint256).max / 200, fee = 2
        // volume = fee * 100 = 200
        // volumeWeightedPrice = (type(uint256).max / 200) * 200
        //   = type(uint256).max - (type(uint256).max % 200)  ← safely below max
        //   >> type(uint256).max / 2                         ← triggers the guard
        uint256 extremePrice = type(uint256).max / 200;
        uint256 largeFee = 2;

        vwapTracker.recordVolumeAndPrice(extremePrice, largeFee);

        // After the cap: volumeWeightedPrice = type(uint256).max / 2
        //                volume             = (type(uint256).max / 2) / extremePrice
        uint256 cappedVWP = type(uint256).max / 2;
        uint256 expectedVolume = cappedVWP / extremePrice;

        assertEq(vwapTracker.cumulativeVolumeWeightedPriceX96(), cappedVWP, "Single-tx overflow: cumulative VWAP should be capped");
        assertEq(vwapTracker.cumulativeVolume(), expectedVolume, "Single-tx overflow: volume should be recalculated from cap");

        // VWAP should equal the extreme price (capped numerator / recalculated denominator)
        assertEq(vwapTracker.getVWAP(), extremePrice, "VWAP should equal the extreme price after cap");
    }

    // ========================================
    // MAXIMUM COMPRESSION FACTOR (>1000x) TEST
    // ========================================

    /**
     * @notice Test that compressionFactor is capped at 1000 when historical data is very large
     * @dev Sets cumulativeVolumeWeightedPriceX96 to type(uint256).max / 100 so that
     *      compressionFactor = (max/100) / (max/10^6) + 1 = 10000 + 1 > 1000 → capped to 1000.
     */
    function testMaxCompressionFactorCapped() public {
        // maxSafeValue = type(uint256).max / 10^6
        // compressionFactor = largeVWAP / maxSafeValue + 1 = (max/100)/(max/10^6) + 1 = 10^4 + 1
        // Since 10^4 + 1 > 1000, it must be capped to 1000.
        uint256 largeVWAP = type(uint256).max / 100;
        uint256 largeVolume = 10 ** 20;

        vm.store(address(vwapTracker), bytes32(uint256(0)), bytes32(largeVWAP));
        vm.store(address(vwapTracker), bytes32(uint256(1)), bytes32(largeVolume));

        vwapTracker.recordVolumeAndPrice(SAMPLE_PRICE_X96, SAMPLE_FEE);

        uint256 compressionFactor = 1000; // capped from 10001
        uint256 newVolume = SAMPLE_FEE * 100;
        uint256 newVWP = SAMPLE_PRICE_X96 * newVolume;

        uint256 expectedCumulativeVWAP = largeVWAP / compressionFactor + newVWP;
        uint256 expectedCumulativeVolume = largeVolume / compressionFactor + newVolume;

        assertEq(
            vwapTracker.cumulativeVolumeWeightedPriceX96(), expectedCumulativeVWAP, "Max compression: cumulative VWAP should be compressed by exactly 1000"
        );
        assertEq(vwapTracker.cumulativeVolume(), expectedCumulativeVolume, "Max compression: cumulative volume should be compressed by exactly 1000");
    }
}
