contract WickedWitches is ERC1155, Ownable {
    
    uint256 public constant WITCH_PRICE   = 40000000000000000;      //WEI 40000000000000000 = 0.04ETH
    uint256 public constant TOTAL_SUPPLY  = 10000;
    uint256 public constant MAX_PURCHASE  = 20;
    
    uint256 private constant BRONZE       = 20001;  //4E21 //1000
    uint256 private constant SILVER       = 20002;  //4E22 //420
    uint256 private constant GOLD         = 20003;  //4E23 //150
    uint256 private constant DIAMOND      = 20004;  //4E24 //30
    
    uint256 public constant CANDY         = 10401;  //28A1 //250 MAX

    uint256 private _currentWitchIdx      = 1;      //[00001 - 10000] {0001 - 2710}
    uint256 private _currentBronzePetIdx  = 10001;  //[10001 - 10100] {2711 - 2774}
    uint256 private _currentSilverPetIdx  = 10101;  //[10101 - 10160] {2775 - 27B0}
    uint256 private _currentGoldPetIdx    = 10161;  //[10161 - 10190] {27B1 - 27CE}
    uint256 private _currentDiamondPetIdx = 10191;  //[10191 - 10205] {27CF - 27DD}
    uint256 private _currentMaskIdx       = 10206;  //[10206 - 10230] {27DE - 27F6}
    
    bool public saleIsActive = false;               //RELEASE = false
    
    event TokenMinted(uint tokenId, address sender);
    
    //CONTRACT META
    string public name   = "Wicked Witches";
    string public symbol = "WW";
    
    constructor() ERC1155("http://wwitches.com/contract/{id}") {
        _mint(msg.sender, CANDY, 250, "");
        //reserve giveaway witches
        for (uint i = 0; i < 30; i++) {
            _mint(msg.sender, _currentWitchIdx, 1, "");
            _currentWitchIdx++;
        }
        //reserve giveaway pets
        for (uint i = 0; i < 5; i++) {
            _mint(msg.sender, _currentDiamondPetIdx, 1, "");
            _currentDiamondPetIdx++;
        }
    }

    function mintWitchTo(uint numberOfTokens) public payable {
        require(saleIsActive, "Mint is not available right now");
        require(numberOfTokens <= MAX_PURCHASE, "Can only mint 20 tokens at a time");
        require(currentWitches()+numberOfTokens <= TOTAL_SUPPLY, "Purchase would exceed max supply");
        require(WITCH_PRICE*numberOfTokens <= msg.value, "Ether value sent is not correct");
        
        for (uint i = 0; i < numberOfTokens; i++) {
            _mint(msg.sender, _currentWitchIdx, 1, "");
            if(_currentWitchIdx * 0x64 % 0x3E5 <= 0x63){
	            _mint(msg.sender, BRONZE, 1, "");
		    }
		    if(_currentWitchIdx * 0x64 % 0x945 <= 0x63){
	            _mint(msg.sender, SILVER, 1, "");
		    }
		    if(_currentWitchIdx * 0x64 % 0x1A0A <= 0x63){
	            _mint(msg.sender, GOLD, 1, "");
		    }
		    if(_currentWitchIdx * 0x25 % 0x247A <= 0x1B){
	            _mint(msg.sender, DIAMOND, 1, "");
		    }
            
            emit TokenMinted(_currentWitchIdx, msg.sender);
            _currentWitchIdx++;
        }
        
    }
    
    function craftBronzePetTo() public payable {
        require(balanceOf(msg.sender, BRONZE) >= 10, "Not enough bronze shards, you need at least 10");
        _burn(msg.sender, BRONZE, 10);
        _mint(msg.sender, _currentBronzePetIdx, 1, "");
        _currentBronzePetIdx++;
    }
    
    function craftSilverPetTo() public payable {
        require(balanceOf(msg.sender, SILVER) >= 7, "Not enough silver shards, you need at least 7");
        _burn(msg.sender, SILVER, 7);
        _mint(msg.sender, _currentSilverPetIdx, 1, "");
        _currentSilverPetIdx++;
    }
    
    function craftGoldPetTo() public payable {
        require(balanceOf(msg.sender, GOLD) >= 5, "Not enough gold shards, you need at least 5");
        _burn(msg.sender, GOLD, 5);
        _mint(msg.sender, _currentGoldPetIdx, 1, "");
        _currentGoldPetIdx++;
    }
    
    function craftDiamondPetTo() public payable {
        require(balanceOf(msg.sender, DIAMOND) >= 3, "Not enough diamond shards, you need at least 3");
        _burn(msg.sender, DIAMOND, 3);
        _mint(msg.sender, _currentDiamondPetIdx, 1, "");
        _currentDiamondPetIdx++;
    }
    
    function craftMaskTo() public payable {
        require(balanceOf(msg.sender, CANDY) >= 10, "Not enough candies, you need at least 10");
        _burn(msg.sender, CANDY, 10);
        _mint(msg.sender, _currentMaskIdx, 1, "");
        _currentMaskIdx++;
    }
    
    //PUBLIC
    function currentWitches() public view returns (uint256) {
        return _currentWitchIdx-1;
    }
    
    function witchesLeft() public view returns (uint256) {
        return TOTAL_SUPPLY - currentWitches();
    }
    
    //OWNER
    function setSaleIsActive() public onlyOwner {
        saleIsActive = !saleIsActive;
    }
    
    function withdraw() public onlyOwner {
        uint balance = address(this).balance;
        payable(msg.sender).transfer(balance);
    }
    
    function setBaseURI(string memory baseURI) public onlyOwner {
        _setURI(baseURI);
    }


}
function setSaleIsActive() public onlyOwner {
    saleIsActive = !saleIsActive;
}

//OWNER