contract Staking is Ownable{
    using SafeMath for uint256;
    
    event Withdraw(address a,uint256 amount);
    event Stake(address a,uint256 amount,uint256 unlocktime);
    
    struct staker{
        uint256 amount;
        uint256 lockedtime;
        uint256 rate;
    }
    
    mapping (address => staker) public _stakers;
    
    IERC20 private _token;
    
    //staking steps
    uint256[] private times;
    uint256[] private rates;
    
    //locked balance in contract
    uint256 public lockedBalance;
    
    
    IERC20 public usdt = IERC20 (0xdAC17F958D2ee523a2206206994597C13D831ec7);
    
    constructor(address token_){
        _token = IERC20(token_);
        times.push(2592000);
        times.push(7776000);
        times.push(15552000);
        times.push(31104000);
        rates.push(1);
        rates.push(5);
        rates.push(12);
        rates.push(30);
        
    }
    
    function stake(uint256 amount,uint256 stakestep) external {
        require(_stakers[msg.sender].amount==0,"already stake exist");
        require(amount!=0 ,"amount must not 0");
        require(times[stakestep]!=0,"lockedtime must not 0");
        
        _token.transferFrom(msg.sender,address(this),amount);
        
        uint256 lockBalance=amount.mul(rates[stakestep].add(100)).div(100);
        lockedBalance=lockedBalance.add(lockBalance);
        
        require(lockedBalance<_token.balanceOf(address(this)),"Stake : staking is full");
        
        _stakers[msg.sender]= staker(lockBalance,block.timestamp.add(times[stakestep]),rates[stakestep]);
        
        emit Stake(msg.sender,lockBalance,block.timestamp.add(times[stakestep]));
    }
    
    function withdraw() external {
        require(_stakers[msg.sender].amount>0,"there is no staked amount");
        require(_stakers[msg.sender].lockedtime<block.timestamp,"not ready to withdraw");
        
        _token.transfer(msg.sender,_stakers[msg.sender].amount);
        _stakers[msg.sender]=staker(0,0,0);
    }
    
    function getlocktime(address a)external view returns (uint256){
        if(block.timestamp>_stakers[a].lockedtime)
            return 0;
        return _stakers[a].lockedtime.sub(block.timestamp);
    }
    
    function getamount(address a)external view returns(uint256){
        return _stakers[a].amount;
    }
    
    function getTotoalAmount() external view returns(uint256){
       return _token.balanceOf(address(this));
    }
    
    
    //for Owner
    function withdrawOwner(uint256 amount) external onlyOwner{
        require(amount<_token.balanceOf(address(this)).sub(lockedBalance));
        _token.transfer(_msgSender(),amount);
    }
    
    function withdrawOwnerETH(uint256 amount) external payable onlyOwner{
        require(address(this).balance>amount);
        _msgSender().transfer(amount);    
    }
    
    function buyforstakingwithexactEHTforToken(uint256 stakestep,uint256 tokenAmount) external payable {
        
        lockedBalance=lockedBalance.add(tokenAmount);
        require(lockedBalance<_token.balanceOf(address(this)),"Stake : staking is full");
        _stakers[msg.sender]=staker(tokenAmount,block.timestamp.add(times[stakestep]),rates[stakestep]);
        payable(owner()).transfer(msg.value);
        emit Stake(msg.sender,tokenAmount,block.timestamp.add(times[stakestep]));
    }
    
    function buyforstakingwithexactUsdtforToken(uint256 stakestep,uint256 amount,uint256 tokenAmount ) external {
        
        usdt.transferFrom(msg.sender,owner(),amount);
        lockedBalance=lockedBalance.add(tokenAmount);
        require(lockedBalance<_token.balanceOf(address(this)),"Stake : staking is full");
        _stakers[msg.sender]=staker(tokenAmount,block.timestamp.add(times[stakestep]),rates[stakestep]);
        
        emit Stake(msg.sender,tokenAmount,block.timestamp.add(times[stakestep]));
    }
    
    
    // function buyforstakingwithEHTforexactToken(uint256 amountOut,uint256 stakestep) external payable {
        
    //     uint256 ETHAmount=tokenPriceIn(amountOut).mul(100-rates[stakestep]).div(100);
    //     require(ETHAmount==msg.value,"buyforstaking : wrong ETH amount");
        
    //     lockedBalance=lockedBalance.add(amountOut);
    //     _stakers[msg.sender]=staker(amountOut,block.timestamp.add(times[stakestep]),rates[stakestep]);
        
    //     emit Stake(msg.sender,amountOut,block.timestamp.add(times[stakestep]));
    // }
    
}
function withdrawOwner(uint256 amount) external onlyOwner{
    require(amount<_token.balanceOf(address(this)).sub(lockedBalance));
    _token.transfer(_msgSender(),amount);
}

//for Owner