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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title MockDVMPool
 * @notice Minimal mock of a DODO PMM pool so DODOPMMIntegration can deploy and create pools on Chain 138
 * @dev Not for production; use real DODO DVM when available. Implements view and swap stubs.
 */
contract MockDVMPool {
    address public baseToken;
    address public quoteToken;
    uint256 public baseReserve;
    uint256 public quoteReserve;
    uint256 public midPrice;
    uint256 public totalSupply;
    mapping(address => uint256) private _shares;
    uint256 public constant _K_ = 0.5e18;       // 50% slippage factor (DODO convention)
    uint256 public constant _LP_FEE_RATE_ = 3; // 0.03% in basis points

    constructor(
        address _baseToken,
        address _quoteToken,
        uint256 _initialPrice
    ) {
        baseToken = _baseToken;
        quoteToken = _quoteToken;
        midPrice = _initialPrice;
        baseReserve = 0;
        quoteReserve = 0;
    }

    function _BASE_TOKEN_() external view returns (address) {
        return baseToken;
    }

    function _QUOTE_TOKEN_() external view returns (address) {
        return quoteToken;
    }

    function _BASE_RESERVE_() external view returns (uint256) {
        return baseReserve;
    }

    function _QUOTE_RESERVE_() external view returns (uint256) {
        return quoteReserve;
    }

    function getVaultReserve() external view returns (uint256, uint256) {
        return (baseReserve, quoteReserve);
    }

    function balanceOf(address owner) external view returns (uint256) {
        return _shares[owner];
    }

    function getMidPrice() external view returns (uint256) {
        return midPrice;
    }

    /// @notice Oracle price (same as mid for mock); enables MCP dodo_pmm_v2_like profile
    function getOraclePrice() external view returns (uint256) {
        return midPrice;
    }

    function querySellBase(address, uint256 amount) external view returns (uint256, uint256) {
        return ((amount * midPrice) / 1e18, 0);
    }

    function querySellQuote(address, uint256 amount) external view returns (uint256, uint256) {
        if (midPrice == 0) {
            return (0, 0);
        }
        return ((amount * 1e18) / midPrice, 0);
    }

    function sellBase(address to) external returns (uint256 receiveQuoteAmount) {
        uint256 baseBal = IERC20(baseToken).balanceOf(address(this));
        require(baseBal >= baseReserve, "MockDVMPool: base");
        uint256 baseInput = baseBal - baseReserve;
        if (baseInput == 0) return 0;
        (receiveQuoteAmount,) = this.querySellBase(address(0), baseInput);
        require(IERC20(quoteToken).transfer(to, receiveQuoteAmount), "MockDVMPool: q");
        baseReserve = IERC20(baseToken).balanceOf(address(this));
        quoteReserve = IERC20(quoteToken).balanceOf(address(this));
    }

    function sellQuote(address to) external returns (uint256 receiveBaseAmount) {
        uint256 quoteBal = IERC20(quoteToken).balanceOf(address(this));
        require(quoteBal >= quoteReserve, "MockDVMPool: quote");
        uint256 quoteInput = quoteBal - quoteReserve;
        if (quoteInput == 0) return 0;
        (receiveBaseAmount,) = this.querySellQuote(address(0), quoteInput);
        require(IERC20(baseToken).transfer(to, receiveBaseAmount), "MockDVMPool: b");
        baseReserve = IERC20(baseToken).balanceOf(address(this));
        quoteReserve = IERC20(quoteToken).balanceOf(address(this));
    }

    function buyShares(address to) external returns (uint256, uint256, uint256) {
        uint256 baseBal = IERC20(baseToken).balanceOf(address(this));
        uint256 quoteBal = IERC20(quoteToken).balanceOf(address(this));
        require(baseBal >= baseReserve && quoteBal >= quoteReserve, "MockDVMPool: reserve");

        uint256 baseInput = baseBal - baseReserve;
        uint256 quoteInput = quoteBal - quoteReserve;
        require(baseInput > 0 && quoteInput > 0, "MockDVMPool: no input");

        uint256 lpShare;
        if (totalSupply == 0) {
            lpShare = baseBal;
            require(lpShare > 2001, "MockDVMPool: MINT_AMOUNT_NOT_ENOUGH");
            totalSupply = lpShare;
            _shares[address(0)] = 1001;
            lpShare -= 1001;
            _shares[to] += lpShare;
        } else {
            uint256 baseShares = (baseInput * totalSupply) / baseReserve;
            uint256 quoteShares = (quoteInput * totalSupply) / quoteReserve;
            lpShare = baseShares < quoteShares ? baseShares : quoteShares;
            totalSupply += lpShare;
            _shares[to] += lpShare;
        }

        baseReserve = baseBal;
        quoteReserve = quoteBal;
        return (baseInput, quoteInput, lpShare);
    }

    function sync() external {
        baseReserve = IERC20(baseToken).balanceOf(address(this));
        quoteReserve = IERC20(quoteToken).balanceOf(address(this));
    }
}
