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

import "@openzeppelin/utils/math/Math.sol";

/**
 * @title VWAPTracker
 * @notice Abstract contract for tracking Volume Weighted Average Price (VWAP) data
 * @dev Provides VWAP calculation and storage functionality that can be inherited by other contracts.
 *      Price inputs are sourced from the current pool tick (pool.slot0()) at the time of each
 *      recenter, giving volume-weighted accuracy without per-swap gas overhead.
 *      The LiquidityManager feeds _recordVolumeAndPrice(currentPriceX96, ethFee) at each recenter.
 *
 * Key features:
 * - Volume-weighted average with data compression (max 1000x compression)
 * - Prevents dormant whale manipulation through historical price memory
 * - Stores price² (squared price) in X96 format for VWAP calculation
 * - Automatic overflow protection by compressing historic data when needed
 * - Price source: current pool tick snapshot at recenter time (not TWAP, not anchor midpoint)
 */
abstract contract VWAPTracker {
    using Math for uint256;

    uint256 public cumulativeVolumeWeightedPriceX96;
    uint256 public cumulativeVolume;

    /**
     * @notice Records volume and price data for VWAP calculation
     * @param currentPriceX96 The current price in Q96 format (price * 2^96, from _priceAtTick)
     * @param fee The fee amount used to calculate volume
     * @dev Assumes fee represents 1% of volume, handles overflow by compressing historic data
     */
    function _recordVolumeAndPrice(uint256 currentPriceX96, uint256 fee) internal {
        // assuming FEE is 1%
        uint256 volume = fee * 100;
        uint256 volumeWeightedPriceX96 = currentPriceX96 * volume;

        // ULTRA-RARE EDGE CASE: Check if the new data itself would overflow even before adding
        // This can only happen with impossibly large transactions (>10,000 ETH + $billion token prices)
        if (volumeWeightedPriceX96 > type(uint256).max / 2) {
            // If a single transaction is this large, cap it to prevent system failure
            // This preserves system functionality while limiting the impact of the extreme transaction
            volumeWeightedPriceX96 = type(uint256).max / 2;
            volume = volumeWeightedPriceX96 / currentPriceX96;
        }
        // Check for potential overflow. 10**70 is close to 2^256
        if (cumulativeVolumeWeightedPriceX96 > 10 ** 70) {
            // CRITICAL: Preserve historical significance for dormant whale protection
            // Find the MINIMUM compression factor needed to prevent overflow
            uint256 maxSafeValue = type(uint256).max / 10 ** 6; // Leave substantial room for future data
            uint256 compressionFactor = (cumulativeVolumeWeightedPriceX96 / maxSafeValue) + 1;

            // Cap maximum compression to preserve historical "eternal memory"
            // Even in extreme cases, historical data should retain significant weight
            if (compressionFactor > 1000) {
                compressionFactor = 1000; // Maximum 1000x compression to preserve history
            }

            // Ensure minimum compression effectiveness
            if (compressionFactor < 2) {
                compressionFactor = 2; // At least 2x compression when triggered
            }

            // Compress both values by the same minimal factor
            cumulativeVolumeWeightedPriceX96 = cumulativeVolumeWeightedPriceX96 / compressionFactor;
            cumulativeVolume = cumulativeVolume / compressionFactor;
        }
        cumulativeVolumeWeightedPriceX96 += volumeWeightedPriceX96;
        cumulativeVolume += volume;
    }

    /**
     * @notice Calculates the current VWAP
     * @return vwapX96 The volume weighted average price in X96 format
     * @dev Returns 0 if no volume has been recorded
     */
    function getVWAP() public view returns (uint256 vwapX96) {
        if (cumulativeVolume > 0) {
            vwapX96 = cumulativeVolumeWeightedPriceX96 / cumulativeVolume;
        } else {
            vwapX96 = 0;
        }
    }

    /**
     * @notice Calculates adjusted VWAP with capital inefficiency factor
     * @param capitalInefficiency The capital inefficiency factor (scaled by 10^18)
     * @return adjustedVwapX96 The adjusted VWAP in X96 format
     * @dev Applies a 70% base weight plus capital inefficiency adjustment
     */
    function getAdjustedVWAP(uint256 capitalInefficiency) public view returns (uint256 adjustedVwapX96) {
        uint256 vwapX96 = getVWAP();
        if (vwapX96 > 0) {
            adjustedVwapX96 = (7 * vwapX96 / 10) + (vwapX96 * capitalInefficiency / 10 ** 18);
        } else {
            adjustedVwapX96 = 0;
        }
    }

    /**
     * @notice Resets VWAP tracking data
     * @dev Can be called by inheriting contracts to reset tracking
     */
    function _resetVWAP() internal {
        cumulativeVolumeWeightedPriceX96 = 0;
        cumulativeVolume = 0;
    }
}
