// File: INextGenAdmins.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

interface INextGenAdmins {

    // retrieve global admin
    function retrieveGlobalAdmin(address _address) external view returns(bool);

    // retrieve function admin
    function retrieveFunctionAdmin(address _address, bytes4 _selector) external view returns(bool);

    // retrieve collection admin
    function retrieveCollectionAdmin(address _address, uint256 _collectionID) external view returns(bool);

    // retrieve if the contract is admin contract
    function isAdminContract() external view returns (bool);

    // retrieve owner
    function owner() external view returns (address);

}
// File: INextGenCore.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

interface INextGenCore {

    function retrievewereDataAdded(uint256 _collectionID) external view returns(bool);

    function viewTokensIndexMin(uint256 _collectionID) external view returns (uint256);

    function viewTokensIndexMax(uint256 _collectionID) external view returns (uint256);

    function viewCirSupply(uint256 _collectionID) external view returns (uint256);

    function airDropTokens(uint256 mintIndex, address _recipient, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID) external;

    function mint(uint256 mintIndex, address _mintingAddress , address _mintTo, string memory _tokenData, uint256 _saltfun_o, uint256 _collectionID, uint256 phase) external;

    function collectionFreezeStatus(uint256 _collectionID) external view returns(bool);

    function viewMaxAllowance(uint256 _collectionID) external view returns (uint256);

    function retrieveTokensMintedALPerAddress(uint256 _collectionID, address _address) external view returns(uint256);

    function retrieveTokensMintedPublicPerAddress(uint256 _collectionID, address _address) external view returns(uint256);

    function viewColIDforTokenID(uint256 _tokenid) external view returns (uint256);

    function burnToMint(uint256 mintIndex, uint256 _burnCollectionID, uint256 _tokenId, uint256 _mintCollectionID, uint256 _saltfun_o, address burner) external;

    function retrieveArtistAddress(uint256 _collectionID) external view returns(address);

    function setTokenHash(uint256 _collectionID, uint256 _mintIndex, bytes32 _hash) external;

    function retrieveTokenHash(uint256 _tokenid) external view returns(bytes32);

}
// File: IXRandoms.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.19;

interface IXRandoms {

    function randomNumber() external view returns (uint256);

    function randomWord() external view returns (string memory);
    
}
// File: RandomizerNXT.sol



// SPDX-License-Identifier: MIT

/**
 *
 *  @title: NextGen 6529 - NXT Randomizer Contract
 *  @date: 20-December-2023
 *  @version: 1.5
 *  @author: 6529 team
 */

pragma solidity ^0.8.19;

import "./IXRandoms.sol";
import "./INextGenAdmins.sol";
import "./INextGenCore.sol";

contract NextGenRandomizerNXT {

    IXRandoms public randoms;
    INextGenAdmins private adminsContract;
    INextGenCore public gencoreContract;
    address gencore;

    constructor(address _randoms, address _admin, address _gencore) {
        randoms = IXRandoms(_randoms);
        adminsContract = INextGenAdmins(_admin);
        gencore = _gencore;
        gencoreContract = INextGenCore(_gencore);
    }

    // certain functions can only be called by a global or function admin

    modifier FunctionAdminRequired(bytes4 _selector) {
      require(adminsContract.retrieveFunctionAdmin(msg.sender, _selector) == true || adminsContract.retrieveGlobalAdmin(msg.sender) == true , "Not allowed");
      _;
    }

    // update contracts if needed

    function updateRandomsContract(address _randoms) public FunctionAdminRequired(this.updateRandomsContract.selector) {
        randoms = IXRandoms(_randoms);
    }

    function updateAdminContract(address _newadminsContract) public FunctionAdminRequired(this.updateAdminContract.selector) {
        require(INextGenAdmins(_newadminsContract).isAdminContract() == true, "Contract is not Admin");
        adminsContract = INextGenAdmins(_newadminsContract);
    }

    function updateCoreContract(address _gencore) public FunctionAdminRequired(this.updateCoreContract.selector) { 
        gencore = _gencore;
        gencoreContract = INextGenCore(_gencore);
    }

    // function that calculates the random hash and returns it to the gencore contract
    function calculateTokenHash(uint256 _collectionID, uint256 _mintIndex, uint256 _saltfun_o) public {
        require(msg.sender == gencore);
        bytes32 hash = keccak256(abi.encodePacked(_mintIndex, blockhash(block.number - 1), randoms.randomNumber(), randoms.randomWord()));
        gencoreContract.setTokenHash(_collectionID, _mintIndex, hash);
    }

    // get randomizer contract status
    function isRandomizerContract() external view returns (bool) {
        return true;
    }
    
}