contract TheScoobs is ERC721Enumerable, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenId;

    enum SaleState {
        PAUSED,
        SURPRISE,
        PRESALE,
        PUBLIC
    }

    SaleState saleState;

    uint256 public constant MAX_SUPPLY = 10000;

    string baseTokenURI;

    uint256 public suprisePrice = 30000000000000000; //0.03 eth
    uint256 public presalePrice = 50000000000000000; //0.05 eth
    uint256 public price = 100000000000000000; //0.1 eth

    mapping(address => bool) public surpriseMinted;
    mapping(address => bool) public presaleMinted;

    event TheScoobsMinted(uint256 tokenId);

    constructor(string memory baseURI) ERC721("The Scoobs", "SCOOBS") {
        setBaseURI(baseURI);
        saleState = SaleState.PAUSED;
    }

    function setBaseURI(string memory baseURI) public onlyOwner {
        baseTokenURI = baseURI;
    }

    function changeSurprisePrice(uint256 _newSuprisePrice) external onlyOwner {
        suprisePrice = _newSuprisePrice;
    }

    function changePresalePrice(uint256 _newPresalePrice) external onlyOwner {
        presalePrice = _newPresalePrice;
    }

    function changePrice(uint256 _newPrice) external onlyOwner {
        price = _newPrice;
    }

    // 0 = Paused
    // 1 = Surprise
    // 2 = Presale
    // 3 = Public
    function changeSaleState(uint8 _newSaleState) external onlyOwner {
        saleState = SaleState(_newSaleState);
    }

    function withdraw() external onlyOwner {
        (bool success, ) = payable(msg.sender).call{
            value: address(this).balance
        }("");
        require(success, "Transfer failed.");
    }

    function suprisePresale() external payable {
        address user = msg.sender;
        require(
            saleState == SaleState.SURPRISE,
            "Surprise sale is not open yet"
        );
        require(
            totalSupply() + 1 <= 500,
            "Purchase will exceed NFTs alloted for suprise presale"
        );
        require(
            !surpriseMinted[user],
            "Address has already minted in Suprise presale"
        );
        require(
            msg.value >= suprisePrice,
            "Ether sent with this transaction is not correct"
        );
        surpriseMinted[user] = true;
        _mint(user);
    }

    function preSale() external payable {
        address user = msg.sender;
        require(saleState == SaleState.PRESALE, "Presale is not open yet");
        require(
            totalSupply() + 1 <= 2500,
            "Purchase will exceed NFTs alloted for presale"
        );
        require(!presaleMinted[user], "Address has already minted in presale");
        require(
            msg.value >= presalePrice,
            "Ether sent with this transaction is not correct"
        );
        presaleMinted[user] = true;
        _mint(user);
    }

    //public mint
    function mint(uint256 _count) external payable {
        require(totalSupply() + _count <= MAX_SUPPLY, "Exceeds maximum supply");
        require(_count > 0, "Minimum 1 NFT should be minted per transaction");
        address _to = msg.sender;
        if (_to != owner()) {
            require(saleState == SaleState.PUBLIC, "Sale is not open yet");
            require(_count <= 5, "Maximum 5 can be minted per transaction");
            require(
                msg.value >= price * _count,
                "Ether sent with this transaction is not correct"
            );
        }
        for (uint256 i = 0; i < _count; i++) {
            _mint(_to);
        }
    }

    function _mint(address _to) private {
        _tokenId.increment();
        uint256 tokenId = _tokenId.current();
        _safeMint(_to, tokenId);
        emit TheScoobsMinted(tokenId);
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return baseTokenURI;
    }
}
function changeSaleState(uint8 _newSaleState) external onlyOwner {
    saleState = SaleState(_newSaleState);
}

// 0 = Paused
// 1 = Surprise
// 2 = Presale
// 3 = Public