// Contract: pubSale
// Target function: function withdrawTokens() public nonReentrant
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.14;
// Imports
/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 */
abstract contract ReentrancyGuard {

    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}

contract pubSale is ReentrancyGuard {
    address public owner = 0xBEED5427b0E728AC7EfAaD279c51d511472f9ee2; // owner
    IERC20 public token; //  Token.
    bool private tokenAvailable = false;
    uint public tokensPerETH = 17500; // token per ETH
    uint public ending; // sale end time
    bool public presaleStarted = false; //started or not
    address public deadWallet = 0x000000000000000000000000000000000000dEaD; 
    uint public cooldownTime = 7 days; // time between withdrawals of token
    uint public tokensSold;
    uint256 internal balance;
    uint256 public ContractBalance = 1500000*10**18; 


    mapping(address => uint) public invested; // how much a person invested.
    mapping(address => uint) public investorBalance;//their current balance
    mapping(address => uint) public withdrawableBalance;//how much they can take out of tha platform
    mapping(address => uint) public claimReady;//is it time for that to happen

    constructor() {
    }

    modifier onlyOwner() {
        require(msg.sender == owner, 'You must be the owner.');
        _;
    }

    function transferOwnership (address newOwner) public onlyOwner{
        //check if not empty
        if (newOwner != 0x0000000000000000000000000000000000000000){
        owner = newOwner;
        }
    }

   //token insertion can only happen 1 time
    function setToken(IERC20 _token) public onlyOwner {
        require(!tokenAvailable, "Token is already inserted.");
        token = _token;
        tokenAvailable = true;
    }

    function setPrice(uint _priceTPETH) public onlyOwner {
        require(presaleStarted, "Presale not started.");
        require(block.timestamp <  ending, "Presale finished.");
        tokensPerETH = _priceTPETH;
    }

    function startSale(uint _presaleTime) public onlyOwner {
        require(tokenAvailable, "Token is not set.");
        require(!presaleStarted, "Presale already started.");
        ending = block.timestamp + _presaleTime;
        presaleStarted = true;
    }

    function invest() public payable nonReentrant {
        require(presaleStarted, "Presale must have started.");
        require(block.timestamp <= ending, "Presale finished.");
        invested[msg.sender] += msg.value; // update investors balance
        require(invested[msg.sender] >= 0.1 ether, "Your investment should be more than 0.1 ETH.");
        require(invested[msg.sender] <= 2 ether, "Your investment cannot exceed 2 ETH.");

        uint _investorTokens = msg.value * tokensPerETH; // how many tokens they will receive
        investorBalance[msg.sender] += _investorTokens;//do the swap
        withdrawableBalance[msg.sender] += _investorTokens;//update the necesary balances
        tokensSold += _investorTokens;
    }

    //% calculation
    function mulScale (uint x, uint y, uint128 scale) internal pure returns (uint) {
        uint a = x / scale;
        uint b = x % scale;
        uint c = y / scale;
        uint d = y % scale;

        return a * c * scale + a * d + b * c + b * d / scale;
    }
    //investors claim function - they claim tokens at the end of the presale