contract KRAKEN is ERC721BaseTKC, Ownable, ReentrancyGuard{
    using Strings for uint256;
    string public provenanceHash;
    string private _tokenBaseURI;
    
    // Sale params
    uint256 public cost = 0.08 ether;
    uint256 public tokensMaxPerTx = 8; // Public sale
    uint256 public tokensMaxPerWallet = 4; // Presale
    uint256 public tokensReserved = 88;
    uint256 public tokensMaxPresaleSupply = 500;
    uint256 public tokensMaxSupply = 888;
    uint256 public totalGifted;
    bool public isPublicSaleActive = false;
    bool public isPresaleActive = false;

    mapping(address => uint256) public presaleAllowlist;

    constructor() ERC721BaseTKC("The Kraken Collective", "KRAKEN") { }
    function mint(uint256 _mintQty) external payable nonReentrant{
        require(isPublicSaleActive, "SALE NOT ACTIVE");
        require(_mintQty <= tokensMaxPerTx, "EXCEEDING MINT LIMIT OF 8/TX");
        require(msg.value >= cost * _mintQty , "INSUFFICIENT ETH");
        uint256 supply = _owners.length;
        require(supply + tokensReserved + _mintQty - totalGifted <= tokensMaxSupply, "EXCEEDING TOTAL SUPPLY");
        for(uint256 i; i < _mintQty; i++) {
            _safeMint(msg.sender, supply++, "");
        }
    }
    function mintPresale(uint256 _mintQty) external payable {
        require(isPresaleActive, "PRESALE NOT ACTIVE");
        require(msg.value >= cost * _mintQty , "INSUFFICIENT ETH");
        uint256 reserve = presaleAllowlist[msg.sender];
        require(reserve > 0, "LOW RESERVE OR USER NOT WHITELISTED");
        require(_mintQty <= reserve, "TRY LESS");
        uint256 supply = _owners.length;
        require(supply + _mintQty - totalGifted <= tokensMaxPresaleSupply, "EXCEEDING MAX PRESALE SUPPLY");
        presaleAllowlist[msg.sender] = reserve - _mintQty;
        delete reserve;
        for(uint256 i; i < _mintQty; i++) {
            _safeMint( msg.sender, supply++, "");
        }
    }
    function gift(address[] calldata recipient, uint[] calldata quantity) external onlyOwner{
        require(recipient.length == quantity.length, "RECIPIENT AND QUANTITY NOT EQUAL LENGTH");
        uint256 totalQuantity = 0;
        uint256 supply = _owners.length;
        for(uint256 i=0; i < quantity.length; i++){
            totalQuantity += quantity[i];
        }
        require(totalQuantity <= tokensReserved, "EXCEEDING RESERVED SUPPLY TXN");
        require(supply + totalQuantity <= tokensMaxSupply, "EXCEEDING TOTAL SUPPLY");
        delete totalQuantity;
        for(uint256 i; i < recipient.length; i++){
            for(uint256 j; j < quantity[i]; j++){
                totalGifted++;
                _safeMint(recipient[i], supply++, "");
            }
        }
    }
    function withdraw() external onlyOwner {
        uint256 sendAmount = address(this).balance;
        bool success;

        address wade = payable(0x096a9d16AFFD7fB6b881dA383723bB10180Cc333);
        address tim = payable(0x1435Db7390300EB252C806df378ecC882c041641);
        address mark = payable(0x1e16870873b28d956f8EBCb5179E518f8A9f89B5);
        address community = payable(0x14967Af4019989557489E2621b22C76d6404D2Cd); 

        (success, ) = wade.call{value: (sendAmount * 174/1000)}("");
        require(success, "Transaction Unsuccessful");

        (success, ) = tim.call{value: (sendAmount * 313/1000)}("");
        require(success, "Transaction Unsuccessful");

        (success, ) = mark.call{value: (sendAmount * 313/1000)}("");
        require(success, "Transaction Unsuccessful");

        (success, ) = community.call{value: (sendAmount * 200/1000)}("");
        require(success, "Transaction Unsuccessful");
    }
    function tokenURI(uint256 tokenId) external view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        return string(abi.encodePacked(_tokenBaseURI, tokenId.toString()));
    }
    // Setters
    function setBaseURI(string calldata URI) external onlyOwner {
        _tokenBaseURI = URI;
    }
    function setprovenanceHash(string calldata _newHash) external onlyOwner {
        provenanceHash = _newHash;
    }
    function settokensMaxSupply(uint256 _newMax) external onlyOwner {
        tokensMaxSupply = _newMax;
    }
    function settokensMaxPresaleSupply(uint256 _newMax) external onlyOwner {
        tokensMaxPresaleSupply = _newMax;
    }
    function settokensMaxPerWallet(uint256 _newMax) external onlyOwner {
        tokensMaxPerWallet = _newMax;
    }
    function presaleSet(address[] calldata _addresses) external onlyOwner {
        for(uint256 i; i < _addresses.length; i++){
            presaleAllowlist[_addresses[i]] = tokensMaxPerWallet;
        }
    }
    function setPreSaleState(bool _newState) public onlyOwner {
        isPresaleActive = _newState;
    }
    function setPublicSaleStatus(bool _newState) public onlyOwner {
        isPublicSaleActive = _newState;
    }
    receive() external payable {}
    fallback() external payable {}
}
//****************************************
//Developed by Mercurial (@Mercurial__me)
//****************************************
function setBaseURI(string calldata URI) external onlyOwner {
    _tokenBaseURI = URI;
}

// Setters