// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "./ERC721A.sol";

contract RespawnNFT is Ownable, ERC721A {
    using Strings for uint256;

    enum MintState {
        NONE,
        GOLDENPASS,
        MERCENARIES,
        CLUTCH,
        SOLDOUT,
        REVEAL
    }

    MintState public currentState;

    string public baseURI;
    string public notRevealURI;

    uint256 public MAX_CLUTCH = 100;
    uint256 public MAX_MERCENARIES = 1000;
    uint256 public MAX_GOLDENPASS = 2350;
    uint256 public MAX_SUPPLY = 3500;
    uint256 public MAX_TEAM = 50;
    uint256 public PRICE_GOLDENPASS = 0.029 ether;
    uint256 public PRICE_MERCENARIES = 0.015 ether;

    address public teamAddress;

    bytes32 public clutchMerkleRoot;
    bytes32 public mercenariesMerkleRoot;
    bytes32 public goldenPassMerkleRoot;

    mapping(address => uint256) public amountperWallet;

    constructor(
        address _teamAddress,
        bytes32 _goldenPassMerkleRoot,
        bytes32 _mercenariesMerkleRoot,
        bytes32 _clutchMerkleRoot,
        string memory _baseURI,
        string memory _notRevealURI
    ) ERC721A("RespawnNFT", "RSPWN") {
        teamAddress = _teamAddress;
        clutchMerkleRoot = _clutchMerkleRoot;
        mercenariesMerkleRoot = _mercenariesMerkleRoot;
        goldenPassMerkleRoot = _goldenPassMerkleRoot;
        baseURI = _baseURI;
        notRevealURI = _notRevealURI;
    }

    modifier callerIsUser() {
        require(tx.origin == msg.sender, "The caller is another contract");
        _;
    }

    modifier atState(MintState state) {
        require(currentState == state, "Not is the moment");
        _;
    }

    modifier validateMemberAddress(
        bytes32[] calldata _merkleProof,
        bytes32 _merkleRoot
    ) {
        bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
        require(
            MerkleProof.verify(_merkleProof, _merkleRoot, leaf),
            "You are not part of this Phase"
        );
        _;
    }

    function GoldenPassMint(
        bytes32[] calldata _proof,
        uint256 quantity
    )
        external
        payable
        callerIsUser
        atState(MintState.GOLDENPASS)
        validateMemberAddress(_proof, goldenPassMerkleRoot)
    {
        require(
            totalSupply() + quantity <= (MAX_GOLDENPASS + MAX_TEAM),
            "Max supply exceeded"
        );
        require(
            amountperWallet[msg.sender] + quantity <= 2,
            "You can only get 2 CASE on the GoldenPass Sale"
        );
        require(
            msg.value >= (PRICE_GOLDENPASS * quantity),
            "Insufficient funds for your CASE"
        );

        amountperWallet[msg.sender] += quantity;
        _safeMint(msg.sender, quantity);
    }

    function MercenariesMint(
        bytes32[] calldata _proof,
        uint256 quantity
    )
        external
        payable
        callerIsUser
        atState(MintState.MERCENARIES)
        validateMemberAddress(_proof, mercenariesMerkleRoot)
    {
        require(
            totalSupply() + quantity <=
                (MAX_MERCENARIES + MAX_GOLDENPASS + MAX_TEAM),
            "Max supply exceeded"
        );

        require(
            amountperWallet[msg.sender] + quantity <= 2,
            "You can only get 2 CASE on the Mercenaries Level Sale"
        );

        require(
            msg.value >= (PRICE_MERCENARIES * quantity),
            "Insufficient funds for your CASE"
        );

        amountperWallet[msg.sender] += quantity;
        _safeMint(msg.sender, quantity);
    }

    function ClutchMint(
        bytes32[] calldata _proof
    )
        external
        payable
        callerIsUser
        atState(MintState.CLUTCH)
        validateMemberAddress(_proof, clutchMerkleRoot)
    {
        require(totalSupply() + 1 <= MAX_SUPPLY, "Max supply exceeded");
        require(
            amountperWallet[msg.sender] < 1,
            "You can only get 1 CASE on the Clutch Level Sale"
        );

        amountperWallet[msg.sender] += 1;
        _safeMint(msg.sender, 1);
    }

    function TeamMint(uint256 _maxTeamMint) external payable onlyOwner {
        _safeMint(teamAddress, _maxTeamMint);
    }

    function tokenURI(
        uint256 _tokenId
    ) public view virtual override returns (string memory) {
        require(_exists(_tokenId), "URI query for nonexistent token");

        if (currentState != MintState.REVEAL) {
            return string(notRevealURI);
        }

        return
            string(abi.encodePacked(baseURI, (_tokenId).toString(), ".json"));
    }

    function withdrawAll(address _wallet) external onlyOwner {
        uint256 balance = address(this).balance;
        payable(_wallet).transfer(balance);
    }

    function setTeamAddress(address _team) external onlyOwner {
        teamAddress = _team;
    }

    function setBaseUri(string memory _baseURI) external onlyOwner {
        baseURI = _baseURI;
    }

    function setMintState(uint256 _step) external onlyOwner {
        currentState = MintState(_step);
    }

    function setNotRevealURI(string memory _uri) external onlyOwner {
        notRevealURI = _uri;
    }

    function setClutchMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
        clutchMerkleRoot = _merkleRoot;
    }

    function setMercenariesMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
        mercenariesMerkleRoot = _merkleRoot;
    }

    function setGoldenPassMerkleRoot(bytes32 _merkleRoot) external onlyOwner {
        goldenPassMerkleRoot = _merkleRoot;
    }

    function setMAXCLUTCH(uint256 cant) external onlyOwner {
        MAX_CLUTCH = cant;
    }

    function setMAXMERCENARIES(uint256 cant) external onlyOwner {
        MAX_MERCENARIES = cant;
    }

    function setMAXGOLDENPASS(uint256 cant) external onlyOwner {
        MAX_GOLDENPASS = cant;
    }

    function setMAX_SUPPLY(uint256 cant) external onlyOwner {
        MAX_SUPPLY = cant;
    }

    function setPRICEGOLDENPASS(uint256 price) external onlyOwner {
        PRICE_GOLDENPASS = price;
    }

    function setPRICEMERCENARIES(uint256 price) external onlyOwner {
        PRICE_MERCENARIES = price;
    }
}
[{"inputs":[{"internalType":"address","name":"_teamAddress","type":"address"},{"internalType":"bytes32","name":"_goldenPassMerkleRoot","type":"bytes32"},{"internalType":"bytes32","name":"_mercenariesMerkleRoot","type":"bytes32"},{"internalType":"bytes32","name":"_clutchMerkleRoot","type":"bytes32"},{"internalType":"string","name":"_baseURI","type":"string"},{"internalType":"string","name":"_notRevealURI","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"}],"name":"ClutchMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"GoldenPassMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"MAX_CLUTCH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_GOLDENPASS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_MERCENARIES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_TEAM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_proof","type":"bytes32[]"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"MercenariesMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"PRICE_GOLDENPASS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_MERCENARIES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTeamMint","type":"uint256"}],"name":"TeamMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"amountperWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"clutchMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentState","outputs":[{"internalType":"enum RespawnNFT.MintState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"goldenPassMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mercenariesMerkleRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"notRevealURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseUri","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setClutchMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setGoldenPassMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cant","type":"uint256"}],"name":"setMAXCLUTCH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cant","type":"uint256"}],"name":"setMAXGOLDENPASS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cant","type":"uint256"}],"name":"setMAXMERCENARIES","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cant","type":"uint256"}],"name":"setMAX_SUPPLY","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_merkleRoot","type":"bytes32"}],"name":"setMercenariesMerkleRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_step","type":"uint256"}],"name":"setMintState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setNotRevealURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"setPRICEGOLDENPASS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"setPRICEMERCENARIES","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_team","type":"address"}],"name":"setTeamAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"teamAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"}],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"}]