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

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

/**
 * @title AereIGP (Interchain Gas Paymaster)
 * @notice Receives AERE fees from outbound cross-chain messages.
 *         Foundation/relayer claims these and uses them to fund the gas paid
 *         on destination chains when delivering inbound messages from AERE.
 *
 *   Hyperlane-compatible interface — apps using Hyperlane's `quoteDispatch` helpers
 *   query us for the AERE fee required to relay a message to a given destination.
 *
 *   Pricing model (configurable per destination):
 *     fee = gasOverhead * gasPriceQuote
 *
 *   gasOverhead = chain-specific gas estimate (e.g. Ethereum ~150k, BSC ~80k).
 *   gasPriceQuote = AERE-denominated quote of destination chain's gas price.
 *     Owner sets this; in v2 we'll pull from AereOracle once cross-chain price
 *     feeds are wired.
 */
contract AereIGP is Ownable {
    struct DestinationConfig {
        uint256 gasOverhead;
        uint256 gasPriceQuoteAere; // wei AERE per unit of destination gas
    }
    mapping(uint32 => DestinationConfig) public destinations;

    address public payoutRecipient;

    event GasPaymentReceived(bytes32 indexed messageId, uint32 destDomain, uint256 amount);
    event DestinationConfigured(uint32 indexed domain, uint256 gasOverhead, uint256 gasPriceQuote);
    event PayoutRecipientChanged(address indexed recipient);

    constructor(address _payoutRecipient) {
        payoutRecipient = _payoutRecipient;
    }

    function configure(uint32 domain, uint256 gasOverhead, uint256 gasPriceQuoteAere) external onlyOwner {
        destinations[domain] = DestinationConfig(gasOverhead, gasPriceQuoteAere);
        emit DestinationConfigured(domain, gasOverhead, gasPriceQuoteAere);
    }

    function setPayoutRecipient(address _r) external onlyOwner {
        payoutRecipient = _r;
        emit PayoutRecipientChanged(_r);
    }

    /// Quote the AERE fee required to relay a message to `destDomain`.
    function quoteGasPayment(uint32 destDomain) external view returns (uint256) {
        DestinationConfig memory c = destinations[destDomain];
        return c.gasOverhead * c.gasPriceQuoteAere;
    }

    /// Called by AereMessenger via postDispatch when a message includes an IGP fee.
    function postDispatch(bytes calldata, bytes calldata data) external payable {
        (bytes32 messageId, uint32 destDomain) = abi.decode(data, (bytes32, uint32));
        emit GasPaymentReceived(messageId, destDomain, msg.value);
    }

    /// Sweep accumulated fees to the payout recipient (relayer's hot wallet).
    function claim() external {
        uint256 bal = address(this).balance;
        require(bal > 0, "AereIGP: nothing to claim");
        (bool ok, ) = payoutRecipient.call{ value: bal }("");
        require(ok, "AereIGP: payout failed");
    }

    receive() external payable {}
}
