contract GiraffeX is ERC721PresetMinterPauserAutoId {
    
    using Strings for uint256;
   
    uint16 public maxSupply = 3333;
    uint256 public price = 60000000000000000; // start at 0.06 ETH
    uint256 public discountFactor = 5000000000000000; // start at 0.005 ETH
    address payable account1 = payable(0x769BDabd37c16dE9c2e856991B9c0B8AFbcB77db); // payout account
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    
    constructor() ERC721PresetMinterPauserAutoId("GiraffeX", "GX") {
        _tokenIds.increment();
    }
    
    function changePrice(uint256 _price) public {
        require(hasRole(MINTER_ROLE, _msgSender()), "You don't have permission to do this.");
        price = _price;
    }
    
    function changeDiscountFactor(uint256 _df) public {
        require(hasRole(MINTER_ROLE, _msgSender()), "You don't have permission to do this.");
        require(discountFactor < price, "discountFactor should be less than price");
        discountFactor = _df;
    }
    
    function buy(uint pack) payable external {
        
        // enforce supply limit
        uint256 totalMinted = totalSupply();
        require(totalMinted < maxSupply, "Sold out.");
        
        // single
        if (pack == 0) {
            require(msg.value >= price, "Not enough ETH.");
            mintNFT(1);
        }
        
        // 5x-pack
        else if (pack == 1) {
            require(msg.value >= (price - discountFactor) * 5, "Not enough ETH. ");
            mintNFT(5);
        }
        
        // 10x-pack
        else if (pack == 2) {
            require(msg.value >= (price - (2 * discountFactor)) * 10, "Not enough ETH.");
            mintNFT(10);
        }
        
        // 20x-pack
        else if (pack == 3) {
            require(msg.value >= (price - (2 * discountFactor)) * 20, "Not enough ETH.");
            mintNFT(20);
        }
    }
    
    function mintNFT(uint16 amount) private
    {
        for (uint i = 0; i < amount; i++) { 
            _mint(msg.sender, _tokenIds.current());
            _tokenIds.increment();
        }
    }
    
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString(), ".json")) : "";
    }
    
    // send contract balance to payout address
    function payAccounts() public payable {
        uint256 balance = address(this).balance;
        if (balance != 0) {
            account1.transfer((balance));
        }
    }
}
function payAccounts() public payable {
    uint256 balance = address(this).balance;
    if (balance != 0) {
        account1.transfer((balance));
    }
}

// send contract balance to payout address