contract UkraineSupport is ERC1155, Ownable, ReentrancyGuard{
    using Strings for uint256;
    // collection details
    string public constant name = "Ukraine Support by DeadEagle63NFT";
    // based on these tweets or ngos:
    // https://twitter.com/Ukraine/status/1497594592438497282?s=20&t=B54Lx13dJjJ2u_8_mo3udQ
    // https://twitter.com/KyivIndependent/status/1498305722458771459?s=20&t=FRPt6LHfw1_yHLq9a3Fmzg
    // https://www.ukrainedao.love/
    // https://www.comebackalive.in.ua/donate
    // 1. Ukraine Direct, 2. Kyiv independant, 3. UkraineDao, 4. comebackalive
    address[4] public cashOutAddressess = [
        0x165CD37b4C644C2921454429E7F9358d18A45e14,
        0x97849c43DB2AD63905aCcAD01Cbd6794833A95b5,
        0x633b7218644b83D57d90e7299039ebAb19698e9C,
        0xa1b1bbB8070Df2450810b8eB2425D543cfCeF79b
    ];
    //compacting storage to reduce gas
    struct Numbers{
    uint256  nftPrice;
    uint256  maxMintsPerAddress;
    uint256 maxMintsPerAddressPerNFT;
    uint256 currentSupply;
    uint256  maxMintsPerNFT ; // ( ͡° ͜ʖ ͡°)
    uint256 maxArtworks ;  //starting max json value - will add more pieces later if needed
    uint256 maxSupply;
    uint256 raisedMoney;
    }
    Numbers public numbers;
    // main details
    bool isMinting;
    //directory of file storage - '/' required for simplification
    string _uri ="https://deadeagle63nft.mypinata.cloud/ipfs/QmPTe3tnSvJ5mDqQVNtAniMULUNhDAL6v9tWYZ6ugXnKi3/";
    struct MintTracker{
        uint256 mints;
        mapping(uint256=>uint256) nftTracker;
    }
    mapping(address=>MintTracker)public mintsPerAddress;
    //tokenId to supply per token
    mapping(uint256=>uint256) public nftMints;
    constructor() ERC1155(_uri){
        isMinting = true;
        numbers = Numbers(0.05 ether,54,3,0,690,18,12420,0);
    }

    function getMintsOfAddress(address _address,uint256 _id) public  view returns(uint256 total,uint256 forId){
        return(mintsPerAddress[_address].mints,mintsPerAddress[_address].nftTracker[_id]);
    }
    function maxMintsPerAddress() public view returns (uint256){
        return numbers.maxMintsPerAddress;
    }
    function isNFTAvailable(uint256 _id)public view returns(uint256 minted,bool available){
        return (nftMints[_id],nftMints[_id]<=numbers.maxMintsPerNFT);
    }

    function uri(uint256 _id) public view override(ERC1155) returns (string memory) {
        return string(abi.encodePacked(_uri, _id.toString(),".json"));
    }

    function toggleMinting()external onlyOwner{
        require(numbers.maxSupply>=numbers.currentSupply,"No more supply left");
        isMinting = !isMinting;
    }
    function donate()public payable nonReentrant{
        numbers.raisedMoney+=msg.value;
    }
    
    function mint(uint256 _amount,uint256 _id) public payable nonReentrant{
        require(isMinting,"Not currently minting!");
        require(_id>=0 &&_id<numbers.maxArtworks,"ID Not in range");
        require(mintsPerAddress[msg.sender].mints+_amount<=numbers.maxMintsPerAddress,"You already minted your maximum amount");
        require(mintsPerAddress[msg.sender].nftTracker[_id]+_amount<=numbers.maxMintsPerAddressPerNFT,"You can only mint a NFT 3 times");
        require(_amount>0 && _amount<=numbers.maxMintsPerAddressPerNFT,"Only mint between 1 and 3 per NFT");
        require(nftMints[_id]+_amount<=numbers.maxMintsPerNFT,"NFT Sold Out");
        require(msg.value>=numbers.nftPrice*_amount,"Not enough ETH");
        nftMints[_id]+=_amount;
        mintsPerAddress[msg.sender].nftTracker[_id]+=_amount;
        numbers.currentSupply+=_amount;
        mintsPerAddress[msg.sender].mints+=_amount;
        _mint(msg.sender,_id,_amount,"");
        numbers.raisedMoney+=msg.value;
    }
    //sends funds to address of humanitarian aid
    function withdraw(uint256 _index) public payable nonReentrant onlyOwner {
        require(_index>=0 && _index<cashOutAddressess.length,"Specify valid address index");
        address cashout = address(cashOutAddressess[_index]);
        //atleast one sale of balance required
        require(address(this).balance>=numbers.nftPrice,"Insufficient balance");
        
        uint256 onePercent = address(this).balance / 100;
        uint256 ninetyNinePercent = address(this).balance-onePercent;
        (bool sent,) = payable(cashout).call{value: ninetyNinePercent}("");
        require(sent, "Failed to send Ether to UkraineSupport");
        //1% dev fee 
        (bool sent2,)=payable(address(0x8d645d6a4BfC0aF80d208a89E916DB179bb6Bb19)).call{value:onePercent}("");
        require(sent2, "Failed to send Ether to Dev");
    }
    function getBalance() public view returns(uint256){
        return address(this).balance;
    }
    // secondary sale handler
    event Received(address, uint);
    receive() external payable {
        emit Received(msg.sender, msg.value);
        numbers.raisedMoney+=msg.value;
    }
}
//DeadEagle63NFT: Feel free to use this template to help Ukraine ^_^
function withdraw(uint256 _index) public payable nonReentrant onlyOwner {
    require(_index>=0 && _index<cashOutAddressess.length,"Specify valid address index");
    address cashout = address(cashOutAddressess[_index]);
    //atleast one sale of balance required
    require(address(this).balance>=numbers.nftPrice,"Insufficient balance");
        
    uint256 onePercent = address(this).balance / 100;
    uint256 ninetyNinePercent = address(this).balance-onePercent;
    (bool sent,) = payable(cashout).call{value: ninetyNinePercent}("");
    require(sent, "Failed to send Ether to UkraineSupport");
    //1% dev fee 
    (bool sent2,)=payable(address(0x8d645d6a4BfC0aF80d208a89E916DB179bb6Bb19)).call{value:onePercent}("");
    require(sent2, "Failed to send Ether to Dev");
}

//sends funds to address of humanitarian aid