contract DarkAgentPool is ERC20("DarkAgentPool", "pDARK"), Ownable {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

// ------------ Multi darklisted_ Tokens rewarding ---------------------------------------

    IERC20 public DARK = IERC20(0x3108ccFd96816F9E663baA0E8c5951D229E8C6da);

    uint256 public darklisted_duration = 100 days;
    uint256 public darklisted_period_finish = 0;
    uint256 public darklisted_last_update_time;
    uint256 public darklisted_newreward;

    address[] public darklisted_token;
    address[] public darklisted_reward_account_list;
    
    mapping(address => bool) public darklisted_staker_accepted;

    mapping(address => uint256) public darklisted_reward_per_token_stored;
    mapping(address => uint256) public darklisted_reward_rate;

    mapping(address => mapping (address => uint)) public darklisted_each_account_rewards;
    mapping(address => mapping (address => uint)) public darklisted_user_reward_per_token_paid;

    event RewardAdded(uint256 darklisted_newreward);
    event Staked(address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount);
    event RewardPaid(address indexed user, uint256 reward);

// ------------ Listing Tokens ---------------------------------------

    function approve_darkListing(address _darklisted_token) external onlyOwner {
        require(_darklisted_token != address(0), "Cannot be adddress(0)");

        darklisted_token.push(_darklisted_token);
    }

    function revoke_darkListing(address _darklisted_token) external onlyOwner {
        require(_darklisted_token != address(0), "Cannot be adddress(0)");

        darklisted_token.pop();
    }

// ------------ Pool Duration ---------------------------------------

    function set_duration(uint256 _darklisted_duration) external onlyOwner {
        require(_darklisted_duration != 0, "Cannot be 0 days");

        darklisted_duration = _darklisted_duration;
    }

    function set_period_finish() external onlyOwner {

        darklisted_period_finish = block.timestamp.add(darklisted_duration);
    }

// ------------ Modifier and Modifier Function ---------------------------------------

    modifier darklisted_updateReward(address account, address token) {
        darklisted_reward_per_token_stored[token] = darklisted_rewardPerToken(token);
        darklisted_last_update_time = darklisted_lastTimeRewardApplicable();
        if (account != address(0)) {
            darklisted_each_account_rewards[account][token] = darklisted_earned(account, token);
            darklisted_user_reward_per_token_paid[account][token] = darklisted_reward_per_token_stored[token];
        }
        _;
    }

    function darklisted_updateReward_function(address account, address token) public {
        darklisted_reward_per_token_stored[token] = darklisted_rewardPerToken(token);
        darklisted_last_update_time = darklisted_lastTimeRewardApplicable();
        if (account != address(0)) {
            darklisted_each_account_rewards[account][token] = darklisted_earned(account, token);
            darklisted_user_reward_per_token_paid[account][token] = darklisted_reward_per_token_stored[token];
        }
    }

// ------------ darklisted_ Rewards Logics--------------------------------

    function darklisted_lastTimeRewardApplicable() public view returns(uint256) {
        return Math.min(block.timestamp, darklisted_period_finish);
    }

    function darklisted_rewardPerToken(address token) public view returns(uint256) {

        if (totalSupply() == 0) {
            return darklisted_reward_per_token_stored[token];
        }

        return darklisted_reward_per_token_stored[token].add(
        darklisted_lastTimeRewardApplicable().sub(darklisted_last_update_time).mul(darklisted_reward_rate[token]).mul(1e18).div(totalSupply())
        );
            
    }
    

    function darklisted_earned(address account, address token) public view returns(uint256) {
        return balanceOf(account).mul(
        darklisted_rewardPerToken(token).sub(darklisted_user_reward_per_token_paid[account][token])
        ).div(1e18).add(darklisted_each_account_rewards[account][token]);

    }

    function stake(uint256 amount) public darklisted_updateReward(msg.sender, 0x3108ccFd96816F9E663baA0E8c5951D229E8C6da) {
        require(amount > 0, "Cannot stake 0");

        if (balanceOf(msg.sender) == 0 && !darklisted_staker_accepted[msg.sender]) {
            darklisted_staker_accepted[msg.sender] = true;
            darklisted_reward_account_list.push(msg.sender);
        }

        _mint(msg.sender, amount);
        DARK.safeTransferFrom(msg.sender, address(this), amount);

    }

    function withdraw(uint256 _share) public darklisted_updateReward(msg.sender, 0x3108ccFd96816F9E663baA0E8c5951D229E8C6da) {
        require(_share > 0, "Cannot withdraw 0");

        if (balanceOf(msg.sender) == 0 && darklisted_staker_accepted[msg.sender]) {
            darklisted_staker_accepted[msg.sender] = false;
            uint256 index = 0;
            while (darklisted_reward_account_list[index] != msg.sender) {
                index++;
            }
            darklisted_reward_account_list[index] = darklisted_reward_account_list[darklisted_reward_account_list.length - 1];
            darklisted_reward_account_list.pop();
        }

        _burn(msg.sender, _share);
        DARK.safeTransfer(msg.sender, _share);
        emit Withdrawn(msg.sender, _share);
    }

    function exit() public {
        withdraw(balanceOf(msg.sender));
        getReward();
    }

    function getReward() public darklisted_updateReward(msg.sender, 0x3108ccFd96816F9E663baA0E8c5951D229E8C6da) {

        uint256 reward = darklisted_earned(msg.sender, 0x3108ccFd96816F9E663baA0E8c5951D229E8C6da);
        if (reward > 0) {
            darklisted_each_account_rewards[msg.sender][0x3108ccFd96816F9E663baA0E8c5951D229E8C6da] = 0;
            DARK.safeTransfer(msg.sender, reward);
            emit RewardPaid(msg.sender, reward);
        }
    }
    
    function getReward_For_All(address account, address token) public darklisted_updateReward(account, token) {

        uint256 reward = darklisted_earned(account, token);
        if (reward > 0) {
            darklisted_each_account_rewards[account][token] = 0;
            IERC20(token).safeTransfer(account, reward);
            emit RewardPaid(account, reward);
        }
    }

    function darklisted_getReward() public {
        for(uint d = 0; d< darklisted_token.length; d++){
            for(uint i = 0; i< darklisted_reward_account_list.length; i++){
                darklisted_updateReward_function(darklisted_reward_account_list[i], darklisted_token[d]);
                uint256 reward = darklisted_earned(darklisted_reward_account_list[i], darklisted_token[d]);
                if (reward > 0) {
                    darklisted_each_account_rewards[darklisted_reward_account_list[i]][darklisted_token[d]] = 0;
                    IERC20(darklisted_token[d]).safeTransfer(darklisted_reward_account_list[i], reward);
                }
            }
        }
    }
    
    function darklisted_getReward_For_All() public {
        for(uint d = 0; d< darklisted_token.length; d++){
            for(uint i = 0; i< darklisted_reward_account_list.length; i++){
                getReward_For_All(darklisted_reward_account_list[i], darklisted_token[d]);
            }
        }
    }    

    function darklisted_notifyRewardAmount() external {

        for(uint d = 0; d< darklisted_token.length; d++){
            darklisted_updateReward_function(address(0), darklisted_token[d]);
            if (darklisted_token[d] == 0x3108ccFd96816F9E663baA0E8c5951D229E8C6da) {
                darklisted_newreward = DARK.balanceOf(address(this)).sub(totalSupply());
            } else {
                darklisted_newreward = IERC20(darklisted_token[d]).balanceOf(address(this));
            }
            if (block.timestamp >= darklisted_period_finish) {
                darklisted_reward_rate[darklisted_token[d]] = darklisted_newreward.div(darklisted_duration);
            } else {
                uint256 remaining = darklisted_period_finish.sub(block.timestamp);
                uint256 leftover = remaining.mul(darklisted_reward_rate[darklisted_token[d]]);
                darklisted_reward_rate[darklisted_token[d]] = darklisted_newreward.add(leftover).div(darklisted_duration);
            }
            darklisted_last_update_time = block.timestamp;
            emit RewardAdded(darklisted_newreward);
        }
    }

    function darklisted_lockedDetails() external view returns (bool, uint256) {
        return (false, darklisted_period_finish);
    }
}
function approve_darkListing(address _darklisted_token) external onlyOwner {
    require(_darklisted_token != address(0), "Cannot be adddress(0)");

    darklisted_token.push(_darklisted_token);
}

// ------------ Listing Tokens ---------------------------------------