contract ERC20 is Context, IERC20, IERC20Metadata, Ownable {
    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    mapping (address => uint256) private _lockedAmounts;
    mapping (address => uint256) private _lockedMonths;
    mapping (address => uint256) private _mintedAmounts;
    mapping (address => uint256) private _mintedTimes;

    mapping (address => bool) private isBlacklisted;


    
     
    constructor (string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    function mintedAmounts(address account) public view virtual returns (uint256) {
        return _mintedAmounts[account];
    }
    
    function mintedTimes(address account) public view virtual returns (uint256) {
        return _mintedTimes[account];
    }

    function unlockedAmountEveryMonth(address account) public view virtual returns (uint256) {
        return _mintedAmounts[account] / 10;
    }

    function lockeddaysNow(address account) public view virtual returns (uint256) {
        return (block.timestamp - _mintedTimes[account]) / 1 days;
    }

    function lockedMonthsAfter1YearNow(address account) public view virtual returns (uint256) {
        return (block.timestamp - _mintedTimes[account] - 365 days) / 30 days;
    }

    function isBlackListed(address user) public view returns(bool) {
        return isBlacklisted[user];
    }    

    
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    function addBlackList(address _user) public onlyOwner{
        require(!isBlacklisted[_user], "user already blacklisted");
        isBlacklisted[_user] = true;
    }

    function removeFromBlacklist(address _user) public onlyOwner {
        require(isBlacklisted[_user], "user already whitelisted");
        isBlacklisted[_user] = false;
        // emit events as well
    } 



    function checklockedAmount(address sender) public returns(uint256 _amount) {
        uint256 _unlockedAmountEveryMonth = 0;
        uint256 _currentTime = block.timestamp;
        // _lockedMonths[sender] = (_currentTime - _mintedTimes[sender]) / 30 days ;
        if(_currentTime <= _mintedTimes[sender] + 365 days)
        {
            return _mintedAmounts[sender] * 99 / 100;
        }
        else{
            _lockedMonths[sender] = (_currentTime - _mintedTimes[sender] - 365 days) / 30 days ;
            _unlockedAmountEveryMonth = _mintedAmounts[sender] * 99 / 1000;
            if (_lockedMonths[sender] >= 10 ) return 0;
            else return ( _mintedAmounts[sender] * 99 / 100 ) - ( _unlockedAmountEveryMonth * _lockedMonths[sender] );
        }        
    }

   
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {        
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        _approve(sender, _msgSender(), currentAllowance - amount);

        return true;
    }

    
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
        return true;
    }

    
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        _approve(_msgSender(), spender, currentAllowance - subtractedValue);

        return true;
    }


    
    
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        if(sender == msg.sender) _lockedAmounts[sender] = 0;
            else _lockedAmounts[sender] = checklockedAmount(sender);
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");
        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");        
        require(amount <= ( _balances[sender] - _lockedAmounts[sender] ), "ERC20: transfer amount exceeds unlocked balance" );        
        require(!isBlacklisted[recipient], "Recipient is blacklisted");
        _balances[sender] = senderBalance - amount;
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);
    }

    
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);
        _mintedAmounts[account] += amount;
        _mintedTimes[account] = block.timestamp;
        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);
    }

    
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        _balances[account] = accountBalance - amount;
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);
    }

    
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

   
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
function balanceOf(address account) public view virtual override returns (uint256) {
    return _balances[account];
}

/**
 * @dev See {IERC20-balanceOf}.
 */