contract CoolAmongUs is ERC721, Ownable {

    bool public saleIsActive = false;
    string private _baseURIextended = "https://coolamongus.s3.us-west-1.amazonaws.com/metadata/coolamongus-metadata-";

    uint256 public Price = 0.015 ether;
	uint public maxPerTx =10;
	uint public maxFreeMintPerWallet = 20;
	uint public amountAvailableFreeMint = 2000;
	uint public maxSupply = 5555;
	address proxyRegistryAddress ; 
	mapping(address => uint) public addressFreeMinted;
	
	
	

    using Counters for Counters.Counter;
    Counters.Counter private _tokenSupply;



    constructor() ERC721("CoolAmongUs", "CAU") {
    }

    function totalSupply() public view returns (uint256 supply) {
        return _tokenSupply.current();
    }

    function setBaseURI(string memory baseURI_) external onlyOwner() {
        _baseURIextended = baseURI_;
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return _baseURIextended;
    }

    function setSaleState(bool newState) public onlyOwner {
        saleIsActive = newState;
    }

    // function isSaleActive() external view returns (bool) {
    //     return saleIsActive;
    // }

    function setPrice(uint256 newPrice) public onlyOwner {
        Price = newPrice;
    }

    // rinkeby: 0xf57b2c51ded3a29e6891aba85459d600256cf317
    // mainnet: 0xa5409ec958c83c3f309868babaca7c86dcb077c1
    function setProxyRegistryAddress(address proxyAddress) external onlyOwner {
        proxyRegistryAddress = proxyAddress;
    }

    function isApprovedForAll(address owner, address operator)
        public
        view
        override
        returns (bool)
    {
        ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
        if (address(proxyRegistry.proxies(owner)) == operator) {
            return true;
        }

        return super.isApprovedForAll(owner, operator);
    }

    function mint(uint numberOfTokens) external payable {
        require(saleIsActive, "Sale is inactive.");
        require(numberOfTokens <= maxPerTx, "You can only mint 10 at a time.");
        require(_tokenSupply.current() + numberOfTokens <= maxSupply, "Purchase would exceed max supply of tokens");
        
        if (_tokenSupply.current() + numberOfTokens > amountAvailableFreeMint) {
            require((Price * numberOfTokens) <= msg.value, "Don't send under (in ETH).");
        } else {
			require(msg.value == 0, "Don't send ether for the free mint.");
			require(addressFreeMinted[msg.sender] < maxFreeMintPerWallet, "You can only adopt 20 free CAU per wallet. Wait for the paid adoption.");
		}
		
		addressFreeMinted[msg.sender] += numberOfTokens;
        for(uint i = 0; i < numberOfTokens; i++) {
		  uint256 _tokenId = _tokenSupply.current() + 1;
            _safeMint(msg.sender, _tokenId);
            _tokenSupply.increment();
        }
    }

     function gift(address _to) external onlyOwner {
        uint256 _tokenId = _tokenSupply.current() + 1;
        _safeMint(_to, _tokenId);
        _tokenSupply.increment();
    }

    function withdraw() public onlyOwner {
        (bool success, ) = msg.sender.call{value: address(this).balance}("");
        require(
            success,
            "Address: unable to send value, recipient may have reverted"
        );
    }

    // function withdraw() public onlyOwner {
    //     uint256 balance = address(this).balance;
    //     Address.sendValue(shareholderAddress, balance);
    // }

}
function setPrice(uint256 newPrice) public onlyOwner {
    Price = newPrice;
}

// function isSaleActive() external view returns (bool) {
//     return saleIsActive;
// }