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

import "@openzeppelin/contracts/access/AccessControl.sol";

/**
 * @title PrivatePoolRegistry
 * @notice Registry of private XAU-anchored stabilization pools (Master Plan Phase 2).
 * @dev Only the Stabilizer (or whitelisted keeper) should execute swaps for rebalancing.
 *      Liquidity provision can be restricted via STABILIZER_LP_ROLE when enforced by a wrapper or runbook.
 */
contract PrivatePoolRegistry is AccessControl {
    bytes32 public constant STABILIZER_LP_ROLE = keccak256("STABILIZER_LP_ROLE");

    /// @dev Canonical key: (token0, token1) where token0 < token1
    mapping(address => mapping(address => address)) private _pools;

    event PrivatePoolRegistered(
        address indexed tokenA,
        address indexed tokenB,
        address indexed pool
    );
    event PrivatePoolRemoved(
        address indexed tokenA,
        address indexed tokenB,
        address indexed pool
    );

    constructor(address admin) {
        require(admin != address(0), "PrivatePoolRegistry: zero admin");
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
    }

    /**
     * @notice Register a private pool for a token pair.
     * @param tokenA First token (order used for storage; getPrivatePool is order-agnostic)
     * @param tokenB Second token
     * @param poolAddress DODO pool address (e.g. from DODOPMMIntegration.createPool)
     */
    function register(
        address tokenA,
        address tokenB,
        address poolAddress
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(tokenA != address(0) && tokenB != address(0), "PrivatePoolRegistry: zero token");
        require(poolAddress != address(0), "PrivatePoolRegistry: zero pool");
        require(tokenA != tokenB, "PrivatePoolRegistry: same token");

        (address t0, address t1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        require(_pools[t0][t1] == address(0), "PrivatePoolRegistry: pool already set");

        _pools[t0][t1] = poolAddress;

        emit PrivatePoolRegistered(tokenA, tokenB, poolAddress);
    }

    /**
     * @notice Remove a private pool registration (e.g. migration).
     */
    function unregister(address tokenA, address tokenB) external onlyRole(DEFAULT_ADMIN_ROLE) {
        (address t0, address t1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        address pool = _pools[t0][t1];
        require(pool != address(0), "PrivatePoolRegistry: not registered");

        delete _pools[t0][t1];
        emit PrivatePoolRemoved(tokenA, tokenB, pool);
    }

    /**
     * @notice Get the private pool for a token pair (order-agnostic).
     * @param tokenIn One of the pair
     * @param tokenOut The other
     * @return pool The registered pool address, or address(0) if none
     */
    function getPrivatePool(address tokenIn, address tokenOut) external view returns (address pool) {
        if (tokenIn == tokenOut) return address(0);
        (address t0, address t1) = tokenIn < tokenOut ? (tokenIn, tokenOut) : (tokenOut, tokenIn);
        return _pools[t0][t1];
    }

    /**
     * @notice Check if an address is allowed to add liquidity (has STABILIZER_LP_ROLE).
     * @dev Use in a wrapper or runbook; DODOPMMIntegration.addLiquidity does not check this.
     */
    function isLpAllowed(address account) external view returns (bool) {
        return hasRole(STABILIZER_LP_ROLE, account);
    }
}
