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

/**
 * @title Supply Corruption Test
 * @notice Regression test for issue #98: KRK Token Supply Corruption During Recenter Operations
 * @dev Verifies that recenter() correctly mints tokens when liquidity increases, preventing deflation
 */
import { Kraiken } from "../src/Kraiken.sol";
import "../src/interfaces/IWETH9.sol";
import "@uniswap-v3-core/interfaces/IUniswapV3Factory.sol";
import "@uniswap-v3-core/interfaces/IUniswapV3Pool.sol";
import "forge-std/Test.sol";

import { LiquidityManager } from "../src/LiquidityManager.sol";
import { Optimizer } from "../src/Optimizer.sol";
import { Stake } from "../src/Stake.sol";
import { TestEnvironment } from "./helpers/TestBase.sol";
import { UniSwapHelper } from "./helpers/UniswapTestBase.sol";

contract SupplyCorruptionTest is UniSwapHelper {
    address constant RECENTER_CALLER = address(0x7777);
    address feeDestination = makeAddr("fees");

    IUniswapV3Factory factory;
    Stake stake;
    LiquidityManager lm;
    Optimizer optimizer;
    TestEnvironment testEnv;

    function setUp() public {
        testEnv = new TestEnvironment(feeDestination);

        (
            IUniswapV3Factory _factory,
            IUniswapV3Pool _pool,
            IWETH9 _weth,
            Kraiken _harberg,
            Stake _stake,
            LiquidityManager _lm,
            Optimizer _optimizer,
            bool _token0isWeth
        ) = testEnv.setupEnvironment(false);

        factory = _factory;
        pool = _pool;
        weth = _weth;
        harberg = _harberg;
        stake = _stake;
        lm = _lm;
        optimizer = _optimizer;
        token0isWeth = _token0isWeth;
    }

    /**
     * @notice Test that recenter does not cause supply corruption
     * @dev Reproduces the bug scenario: after buying tokens and calling recenter,
     *      totalSupply should increase or stay the same, never decrease
     */
    function testRecenterDoesNotCorruptSupply() public {
        // Fund liquidity manager with ETH
        vm.deal(address(lm), 10 ether);

        // Initial recenter to set up positions
        vm.prank(RECENTER_CALLER);
        lm.recenter();

        // Record initial state
        uint256 initialTotalSupply = harberg.totalSupply();
        (address liquidityManagerAddr, address stakingPool) = harberg.peripheryContracts();
        uint256 initialStakingBalance = harberg.balanceOf(stakingPool);

        assertGt(initialTotalSupply, 0, "Initial total supply should be positive");
        console.log("Initial totalSupply:", initialTotalSupply);
        console.log("Initial staking balance:", initialStakingBalance);

        // Simulate user buying tokens (price movement)
        vm.deal(account, 5 ether);
        vm.prank(account);
        weth.deposit{ value: 5 ether }();

        // Perform swap to move price
        performSwap(5 ether, true);

        console.log("Performed 5 ETH swap to move price");
        vm.warp(block.timestamp + 61); // TWAP catches up to post-swap price; cooldown passes

        // Call recenter
        vm.prank(RECENTER_CALLER);
        lm.recenter();

        // Check final state
        uint256 finalTotalSupply = harberg.totalSupply();
        uint256 finalStakingBalance = harberg.balanceOf(stakingPool);

        console.log("Final totalSupply:", finalTotalSupply);
        console.log("Final staking balance:", finalStakingBalance);

        // CRITICAL ASSERTION: Total supply should not decrease
        assertGe(finalTotalSupply, initialTotalSupply, "BUG #98: Total supply should not decrease during recenter");

        // Staking pool ratio should be maintained (within 1% tolerance for rounding)
        if (initialTotalSupply > 0) {
            uint256 initialRatio = (initialStakingBalance * 10_000) / initialTotalSupply;
            uint256 finalRatio = (finalStakingBalance * 10_000) / finalTotalSupply;
            uint256 ratioDiff = finalRatio > initialRatio ? finalRatio - initialRatio : initialRatio - finalRatio;

            assertLt(
                ratioDiff,
                100, // 1% tolerance (100 out of 10000)
                "Staking pool ratio should be maintained"
            );
        }
    }

    /**
     * @notice Test multiple recenter operations don't accumulate supply corruption
     */
    function testMultipleRecentersPreserveSupply() public {
        vm.deal(address(lm), 20 ether);

        // Initial recenter
        vm.prank(RECENTER_CALLER);
        lm.recenter();

        uint256 initialTotalSupply = harberg.totalSupply();
        console.log("Initial supply:", initialTotalSupply);

        // Perform multiple recenter cycles
        uint256 ts = block.timestamp; // track time explicitly to avoid Forge block.timestamp reset
        for (uint256 i = 0; i < 3; i++) {
            // Swap to move price
            vm.deal(account, 2 ether);
            vm.prank(account);
            weth.deposit{ value: 2 ether }();

            performSwap(2 ether, true);
            ts += 61; // TWAP catches up; cooldown passes
            vm.warp(ts);

            vm.prank(RECENTER_CALLER);
            lm.recenter();

            uint256 currentSupply = harberg.totalSupply();
            console.log("Supply after recenter", i + 1, ":", currentSupply);

            assertGe(currentSupply, initialTotalSupply, "Supply should not decrease across multiple recenters");
        }
    }
}
