contract TokenSale is OwnableUpgradeSafe {
    using SafeMath for uint256;

    // Contract state: exchange rate and token
    uint256 public multiplier;
    uint256 public divisor;
    IERC20 public token;
    uint256 public commissionMultiplier;
    uint256 public commissionDivisor;

    event purchaseEvent(address sender, address recommender, uint256 amount);
    event withdrawalETHEvent(address sender, uint256 amount);
    event withdrawTokenEvent(address sender, uint256 amount);

    // Initializer function (replaces constructor)
    function initialize(uint256 _multiplier, uint256 _divisor, uint256 _commissionMultiplier, uint256 _commissionDivisor, IERC20 _token) public initializer {
        OwnableUpgradeSafe.__Ownable_init();
        multiplier = _multiplier;
        divisor = _divisor;
        token = _token;
        commissionMultiplier = _commissionMultiplier;
        commissionDivisor = _commissionDivisor;
    }

    // Send tokens back to the sender using predefined exchange rate
    function buyToken(address _recommenderAddress) external payable {
        uint256 tokens = msg.value.mul(multiplier).div(divisor);
        require(tokens <= token.balanceOf(address(this)), "Insufficient tokens for you to purchase");
        require(msg.sender != _recommenderAddress,"You cannot recommend yourself");

        if(_recommenderAddress == address(0)){
            token.transfer(msg.sender, tokens);
        }else{
            token.transfer(msg.sender, tokens);

            //Commissions
            uint256 commissions = tokens.mul(commissionMultiplier).div(commissionDivisor);
            token.transfer(_recommenderAddress, commissions);
        }

        emit purchaseEvent(msg.sender, _recommenderAddress, tokens);
    }

    //Calculate expected rate
    function calculateExchangeRate(uint256 ethAmount) public view returns (uint256){
        uint256 tokens = ethAmount.mul(multiplier).div(divisor);
        return tokens;
    }

    //Withdrawal of ETH
    function withdrawETH() public onlyOwner {
        msg.sender.transfer(address(this).balance);

        emit withdrawalETHEvent(msg.sender, address(this).balance);
    }

    //Withdrawal of token
    function withdrawToken() public onlyOwner {
        token.transfer(msg.sender, token.balanceOf(address(this)));
        
        emit withdrawTokenEvent(msg.sender, token.balanceOf(address(this)));
    }

    //Show balance tokens
    function getTokenBalance() view public returns (uint256) {
        return token.balanceOf(address(this));
    }

    //Show ETH balance
    function getETHBalance() view public onlyOwner returns (uint256){
        return address(this).balance;
    }
}
//Import access control
// Import base Initializable contract
//import "@openzeppelin/upgrades/contracts/Initializable.sol";
// Import the IERC20 interface and and SafeMath library
function getETHBalance() view public onlyOwner returns (uint256){
    return address(this).balance;
}

//Show ETH balance