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

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

/**
 * @notice Batch ERC-20 drops for EI matrix mainnet top-ups (cWUSDT / cWUSDC).
 * @dev Multicall3 transferFrom is not viable on mainnet cW* (allowance does not persist for MC3).
 *      Operator prefunds this contract, then calls dropPrefunded() — ~100 recipients per tx.
 *      msg.sender must be owner (deployer EOA).
 */
contract EiMatrixMainnetBatchDrop {
    using SafeERC20 for IERC20;

    address public immutable owner;

    event BatchDrop(address indexed token, address indexed operator, uint256 recipientCount, uint256 totalAmount);

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "EiMatrixBatchDrop: not owner");
        _;
    }

    /// @dev Transfer `amounts[i]` from this contract's token balance to `recipients[i]`.
    function dropPrefunded(
        address token,
        address[] calldata recipients,
        uint256[] calldata amounts
    ) external onlyOwner {
        uint256 n = recipients.length;
        require(n == amounts.length, "EiMatrixBatchDrop: length mismatch");
        uint256 total;
        for (uint256 i; i < n; ) {
            uint256 amount = amounts[i];
            total += amount;
            IERC20(token).safeTransfer(recipients[i], amount);
            unchecked {
                ++i;
            }
        }
        emit BatchDrop(token, msg.sender, n, total);
    }

    /// @dev Pull total from owner via transferFrom then distribute (one tx if allowance to this contract works).
    function pullAndDrop(
        address token,
        address[] calldata recipients,
        uint256[] calldata amounts
    ) external onlyOwner {
        uint256 n = recipients.length;
        require(n == amounts.length, "EiMatrixBatchDrop: length mismatch");
        uint256 total;
        for (uint256 i; i < n; ) {
            total += amounts[i];
            unchecked {
                ++i;
            }
        }
        IERC20(token).safeTransferFrom(owner, address(this), total);
        for (uint256 i; i < n; ) {
            IERC20(token).safeTransfer(recipients[i], amounts[i]);
            unchecked {
                ++i;
            }
        }
        emit BatchDrop(token, msg.sender, n, total);
    }

    /// @dev Recover stray tokens (operator only).
    function sweep(address token, address to, uint256 amount) external onlyOwner {
        IERC20(token).safeTransfer(to, amount);
    }
}
