contract TestMixinStakingPoolRewards is
    TestStakingNoWETH
{
    // solhint-disable no-simple-event-func-name
    event UpdateCumulativeReward(
        bytes32 poolId
    );

    event WithdrawAndSyncDelegatorRewards(
        bytes32 poolId,
        address delegator
    );

    struct UnfinalizedPoolReward {
        uint256 reward;
        uint256 membersStake;
    }

    constructor() public {
        _addAuthorizedAddress(msg.sender);
        init();
        _removeAuthorizedAddressAtIndex(msg.sender, 0);
    }

    // Rewards returned by `_computeMemberRewardOverInterval()`, indexed
    // by `_getMemberRewardOverIntervalHash()`.
    mapping (bytes32 => uint256) private _memberRewardsOverInterval;
    // Rewards returned by `_getUnfinalizedPoolRewards()`, indexed by pool ID.
    mapping (bytes32 => UnfinalizedPoolReward) private _unfinalizedPoolRewards;

    // Set pool `rewardsByPoolId`.
    function setPoolRewards(
        bytes32 poolId,
        uint256 _rewardsByPoolId
    )
        external
    {
        rewardsByPoolId[poolId] = _rewardsByPoolId;
    }

    // Set `wethReservedForPoolRewards`.
    function setWethReservedForPoolRewards(
        uint256 _wethReservedForPoolRewards
    )
        external
    {
        wethReservedForPoolRewards = _wethReservedForPoolRewards;
    }

    // Set the rewards returned by a call to `_computeMemberRewardOverInterval()`.
    function setMemberRewardsOverInterval(
        bytes32 poolId,
        uint256 memberStakeOverInterval,
        uint256 beginEpoch,
        uint256 endEpoch,
        uint256 reward
    )
        external
    {
        bytes32 rewardHash = _getMemberRewardOverIntervalHash(
            poolId,
            memberStakeOverInterval,
            beginEpoch,
            endEpoch
        );
        _memberRewardsOverInterval[rewardHash] = reward;
    }

    // Set the rewards returned by `_getUnfinalizedPoolRewards()`.
    function setUnfinalizedPoolRewards(
        bytes32 poolId,
        uint256 reward,
        uint256 membersStake
    )
        external
    {
        _unfinalizedPoolRewards[poolId] = UnfinalizedPoolReward(
            reward,
            membersStake
        );
    }

    // Set `currentEpoch`.
    function setCurrentEpoch(uint256 epoch) external {
        currentEpoch = epoch;
    }

    // Expose `_syncPoolRewards()` for testing.
    function syncPoolRewards(
        bytes32 poolId,
        uint256 reward,
        uint256 membersStake
    )
        external
        returns (uint256 operatorReward, uint256 membersReward)
    {
        return _syncPoolRewards(poolId, reward, membersStake);
    }

    // Expose `_withdrawAndSyncDelegatorRewards()` for testing.
    function withdrawAndSyncDelegatorRewards(
        bytes32 poolId,
        address member
    )
        external
    {
        return _withdrawAndSyncDelegatorRewards(
            poolId,
            member
        );
    }

    // Expose `_computePoolRewardsSplit()` for testing.
    function computePoolRewardsSplit(
        uint32 operatorShare,
        uint256 totalReward,
        uint256 membersStake
    )
        external
        pure
        returns (uint256 operatorReward, uint256 membersReward)
    {
        return _computePoolRewardsSplit(
            operatorShare,
            totalReward,
            membersStake
        );
    }

    // Access `_delegatedStakeToPoolByOwner`
    function delegatedStakeToPoolByOwner(address member, bytes32 poolId)
        external
        view
        returns (IStructs.StoredBalance memory balance)
    {
        return _delegatedStakeToPoolByOwner[member][poolId];
    }

    // Set `_delegatedStakeToPoolByOwner`
    function setDelegatedStakeToPoolByOwner(
        address member,
        bytes32 poolId,
        IStructs.StoredBalance memory balance
    )
        public
    {
        _delegatedStakeToPoolByOwner[member][poolId] = balance;
    }

    // Set `_poolById`.
    function setPool(
        bytes32 poolId,
        IStructs.Pool memory pool
    )
        public
    {
        _poolById[poolId] = pool;
    }

    // Overridden to emit an event.
    function _withdrawAndSyncDelegatorRewards(
        bytes32 poolId,
        address member
    )
        internal
    {
        emit WithdrawAndSyncDelegatorRewards(poolId, member);
        return MixinStakingPoolRewards._withdrawAndSyncDelegatorRewards(
            poolId,
            member
        );
    }

    // Overridden to use `_memberRewardsOverInterval`
    function _computeMemberRewardOverInterval(
        bytes32 poolId,
        uint256 memberStakeOverInterval,
        uint256 beginEpoch,
        uint256 endEpoch
    )
        internal
        view
        returns (uint256 reward)
    {
        bytes32 rewardHash = _getMemberRewardOverIntervalHash(
            poolId,
            memberStakeOverInterval,
            beginEpoch,
            endEpoch
        );
        return _memberRewardsOverInterval[rewardHash];
    }

    // Overridden to use `_unfinalizedPoolRewards`
    function _getUnfinalizedPoolRewards(
        bytes32 poolId
    )
        internal
        view
        returns (uint256 reward, uint256 membersStake)
    {
        (reward, membersStake) = (
            _unfinalizedPoolRewards[poolId].reward,
            _unfinalizedPoolRewards[poolId].membersStake
        );
    }

    // Overridden to just increase `currentEpoch`.
    function _loadCurrentBalance(IStructs.StoredBalance storage balancePtr)
        internal
        view
        returns (IStructs.StoredBalance memory balance)
    {
        balance = balancePtr;
        balance.currentEpoch += 1;
    }

    // Overridden to revert if a pool has unfinalized rewards.
    function _assertPoolFinalizedLastEpoch(bytes32 poolId)
        internal
        view
    {
        require(
            _unfinalizedPoolRewards[poolId].membersStake == 0,
            "POOL_NOT_FINALIZED"
        );
    }

    // Overridden to just emit an event.
    function _updateCumulativeReward(bytes32 poolId)
        internal
    {
        emit UpdateCumulativeReward(poolId);
    }

    // Compute a hash to index `_memberRewardsOverInterval`
    function _getMemberRewardOverIntervalHash(
        bytes32 poolId,
        uint256 memberStakeOverInterval,
        uint256 beginEpoch,
        uint256 endEpoch
    )
        private
        pure
        returns (bytes32 rewardHash)
    {
        return keccak256(
            abi.encode(
                poolId,
                memberStakeOverInterval,
                beginEpoch,
                endEpoch
            )
        );
    }
}
function _withdrawAndSyncDelegatorRewards(
    bytes32 poolId,
    address member
)
    internal
{
    emit WithdrawAndSyncDelegatorRewards(poolId, member);
    return MixinStakingPoolRewards._withdrawAndSyncDelegatorRewards(
        poolId,
        member
    );
}

// Overridden to emit an event.