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

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

interface IBurnVault {
    function burn() external payable;
}

/**
 * @title AereCoinbaseSplitter
 * @notice Routes validator coinbase rewards through an atomic split:
 *           burnBps to AereFeeBurnVault (default 3750 = 37.5%, matching whitepaper §3.3),
 *           remainder back to the validator's address.
 *
 *   Validators (or their forwarder daemons) call `splitAndDistribute()` with
 *   their accumulated coinbase as msg.value. The contract atomically:
 *     1. Sends burnBps/10000 of msg.value to AereFeeBurnVault.
 *     2. Sends the remainder back to the validator's address.
 *     3. Emits Burned + Distributed events with cumulative totals.
 *
 *   Anyone can call this contract — there is no allowlist of "who can burn."
 *   The splitter is owner-configurable only for the burnBps parameter and
 *   the burn-vault address; it cannot hold or steal funds.
 *
 *   Cumulative on-chain accounting allows /network-status to display a live
 *   burn rate, and any third-party explorer or analyst to verify the
 *   whitepaper §3.3 deflation claim in O(1) reads.
 */
contract AereCoinbaseSplitter is Ownable, ReentrancyGuard {
    /// AereFeeBurnVault — where the burned portion goes.
    address payable public burnVault;

    /// Burn rate in basis points. 3750 = 37.5% (matches whitepaper §3.3).
    uint256 public burnBps = 3750;
    uint256 public constant BPS = 10_000;

    /// Cumulative AERE burned through this splitter (lifetime).
    uint256 public totalBurned;
    /// Cumulative AERE distributed back to validators (lifetime).
    uint256 public totalDistributed;
    /// Per-validator (or per-caller) cumulative burn contribution.
    mapping(address => uint256) public burnedBy;
    mapping(address => uint256) public distributedTo;

    event Burned(address indexed contributor, uint256 amount, uint256 newTotalBurned);
    event Distributed(address indexed validator, uint256 amount, uint256 newTotalDistributed);
    event BurnBpsChanged(uint256 oldBps, uint256 newBps);
    event BurnVaultChanged(address oldVault, address newVault);

    constructor(address payable _burnVault) {
        require(_burnVault != address(0), "Splitter: zero vault");
        burnVault = _burnVault;
    }

    // ───────────────────── Admin ─────────────────────

    /// Foundation can adjust the burn rate up to a hard cap of 50% — never higher.
    /// The whitepaper says "up to 37.5%" so this provides headroom but caps abuse.
    function setBurnBps(uint256 _bps) external onlyOwner {
        require(_bps <= 5000, "Splitter: bps too high");
        emit BurnBpsChanged(burnBps, _bps);
        burnBps = _bps;
    }

    function setBurnVault(address payable _vault) external onlyOwner {
        require(_vault != address(0), "Splitter: zero vault");
        emit BurnVaultChanged(burnVault, _vault);
        burnVault = _vault;
    }

    // ───────────────────── Core ─────────────────────

    /**
     * @notice Split msg.value: burnBps/10000 to AereFeeBurnVault, remainder to `validator`.
     * @param validator The address to receive the unburned portion. For validator-
     *                  initiated calls this is typically tx.origin or msg.sender;
     *                  the caller decides where their rebate goes.
     */
    function splitAndDistribute(address payable validator) external payable nonReentrant {
        require(msg.value > 0, "Splitter: zero amount");
        require(validator != address(0), "Splitter: zero validator");

        uint256 burnAmount = (msg.value * burnBps) / BPS;
        uint256 distributeAmount = msg.value - burnAmount;

        // Send burnAmount to AereFeeBurnVault.
        if (burnAmount > 0) {
            IBurnVault(burnVault).burn{ value: burnAmount }();
            totalBurned += burnAmount;
            burnedBy[msg.sender] += burnAmount;
            emit Burned(msg.sender, burnAmount, totalBurned);
        }

        // Distribute remainder back to validator.
        if (distributeAmount > 0) {
            (bool ok, ) = validator.call{ value: distributeAmount }("");
            require(ok, "Splitter: distribute failed");
            totalDistributed += distributeAmount;
            distributedTo[validator] += distributeAmount;
            emit Distributed(validator, distributeAmount, totalDistributed);
        }
    }

    /// Convenience: validator calls this with no validator argument — distributes back to msg.sender.
    function splitToSelf() external payable nonReentrant {
        require(msg.value > 0, "Splitter: zero amount");
        uint256 burnAmount = (msg.value * burnBps) / BPS;
        uint256 distributeAmount = msg.value - burnAmount;

        if (burnAmount > 0) {
            IBurnVault(burnVault).burn{ value: burnAmount }();
            totalBurned += burnAmount;
            burnedBy[msg.sender] += burnAmount;
            emit Burned(msg.sender, burnAmount, totalBurned);
        }
        if (distributeAmount > 0) {
            (bool ok, ) = payable(msg.sender).call{ value: distributeAmount }("");
            require(ok, "Splitter: distribute failed");
            totalDistributed += distributeAmount;
            distributedTo[msg.sender] += distributeAmount;
            emit Distributed(msg.sender, distributeAmount, totalDistributed);
        }
    }

    /// Read the live cumulative burn statistics for /network-status display.
    function burnStats() external view returns (
        uint256 lifetimeBurned,
        uint256 lifetimeDistributed,
        uint256 currentBurnBps
    ) {
        return (totalBurned, totalDistributed, burnBps);
    }
}
