// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Test, console} from "forge-std/Test.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

interface IDODOPMMIntegrationSeedFork {
    function isRegisteredPool(address pool) external view returns (bool);
    function addLiquidity(address pool, uint256 baseAmount, uint256 quoteAmount)
        external
        returns (uint256 baseShare, uint256 quoteShare, uint256 lpShare);
}

interface IDODOPMMPoolSeedFork {
    function _BASE_TOKEN_() external view returns (address);
    function _QUOTE_TOKEN_() external view returns (address);
    function getVaultReserve() external view returns (uint256 baseReserve, uint256 quoteReserve);
    function getMidPrice() external view returns (uint256);
}

/// @notice Mainnet fork validation for permanent cWUSDC/USDC and cWUSDT/USDT DODO seed paths.
contract SeedMainnetCwStablePoolPermanentForkTest is Test {
    using SafeERC20 for IERC20;

    address internal constant INTEGRATION = 0xa9F284eD010f4F7d7F8F201742b49b9f58e29b84;
    address internal constant POOL_USDC = 0x69776fc607e9edA8042e320e7e43f54d06c68f0E;
    address internal constant POOL_USDT = 0x79156F6B7bf71a1B72D78189B540A89A6C13F6FC;
    address internal constant CWUSDC = 0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a;
    address internal constant CWUSDT = 0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE;
    address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
    address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;

    uint256 internal constant SEED_RAW = 50_000_000_000;

    function setUp() public {
        string memory rpc = vm.envOr("ETHEREUM_MAINNET_RPC", string("https://eth.llamarpc.com"));
        vm.createSelectFork(rpc);
    }

    function test_fork_seed_cWUSDC_USDC_addLiquidity_50k() public {
        _seedRail(POOL_USDC, CWUSDC, USDC, "USDC");
    }

    function test_fork_seed_cWUSDT_USDT_addLiquidity_50k() public {
        _seedRail(POOL_USDT, CWUSDT, USDT, "USDT");
    }

    function _ensurePoolRegistered(address pool) internal view {
        assertTrue(IDODOPMMIntegrationSeedFork(INTEGRATION).isRegisteredPool(pool), "pool not registered on integration");
    }

    function _seedRail(address pool, address baseToken, address quoteToken, string memory label) internal {
        address user = makeAddr("seedUser");
        deal(baseToken, user, SEED_RAW);
        deal(quoteToken, user, SEED_RAW);

        IDODOPMMPoolSeedFork poolView = IDODOPMMPoolSeedFork(pool);
        assertEq(poolView._BASE_TOKEN_(), baseToken, "base token");
        assertEq(poolView._QUOTE_TOKEN_(), quoteToken, "quote token");

        _ensurePoolRegistered(pool);

        (uint256 baseBefore, uint256 quoteBefore) = poolView.getVaultReserve();
        uint256 midBefore = poolView.getMidPrice();
        console.log(string.concat(label, " baseReserveBefore"), baseBefore);
        console.log(string.concat(label, " quoteReserveBefore"), quoteBefore);
        console.log(string.concat(label, " midBefore"), midBefore);

        vm.startPrank(user);
        IERC20(baseToken).forceApprove(INTEGRATION, SEED_RAW);
        IERC20(quoteToken).forceApprove(INTEGRATION, SEED_RAW);
        (uint256 baseShare, uint256 quoteShare, uint256 lpShare) =
            IDODOPMMIntegrationSeedFork(INTEGRATION).addLiquidity(pool, SEED_RAW, SEED_RAW);
        vm.stopPrank();

        (uint256 baseAfter, uint256 quoteAfter) = poolView.getVaultReserve();
        uint256 midAfter = poolView.getMidPrice();
        console.log(string.concat(label, " baseShare"), baseShare);
        console.log(string.concat(label, " quoteShare"), quoteShare);
        console.log(string.concat(label, " lpShare"), lpShare);
        console.log(string.concat(label, " baseReserveAfter"), baseAfter);
        console.log(string.concat(label, " quoteReserveAfter"), quoteAfter);
        console.log(string.concat(label, " midAfter"), midAfter);

        assertGt(baseShare, 0, "base share");
        assertGt(quoteShare, 0, "quote share");
        assertGt(lpShare, 0, "lp share");
        assertGt(baseAfter, baseBefore, "base reserve increased");
        assertGt(quoteAfter, quoteBefore, "quote reserve increased");
    }
}
