// Contract: CryptoshackStaking
// Target function: function claim(uint[] calldata tokenIds, bool unstake) external noContracts
// contracts/CryptoshackStaking.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

interface ICryptoshackContract {
    function balanceOf(address owner) external view returns (uint256);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    function transfer(address recipient, uint256 amount) external returns (bool);
}

interface IWorldTokenContract {
    function transferFrom(address from, address to, uint256 tokenId) external;
}

contract CryptoshackStaking {
    // contract owner
    address public owner;
    // reward token contract
    ICryptoshackContract worldTokenContract;
    // staking token contract
    IWorldTokenContract cryptoshackContract;

    // is staking allowed or not
    bool public stakingAllowed;

    bool public emergencyMode;

    uint public undistributed;

    // total reward tokens claimed
    uint public totalClaimed;
    // general info by token type
    uint[3][5] typeToNumbers;
    
    // token Id to staker
    mapping(uint => address) idToStaker;
    // staker to all staked tokens IDs
    mapping(address => uint[]) stakerToIds;
    // token ID to it's index in stakerToIds
    mapping(uint => uint) tokenIdToStakerIndex;
    // token ID to reward tokens claimed
    mapping(uint => uint) tokenToClaimed;

    constructor() { 
        owner=msg.sender; 

        // staked | allocation percent | reward accumulated
        typeToNumbers[0]=[0,50,0];
        typeToNumbers[1]=[0,50,0];
        typeToNumbers[2]=[0,30,0];
        typeToNumbers[3]=[0,20,0];
        typeToNumbers[4]=[0,20,0];
    }

    // stake tokens
    function stake(uint[] calldata tokenIds) external onlyStakingAllowed noContracts {
        uint tokenId;
        uint tokenType;
        for (uint i;i<tokenIds.length;i++) {
            tokenId=tokenIds[i];
            tokenType=tokenId/10000;

            // increase staked tokens of a type amount
            typeToNumbers[tokenType][0]++;
            // set claimed level to the current reward
            tokenToClaimed[tokenId]=typeToNumbers[tokenType][2];
            // set staker
            idToStaker[tokenId]=msg.sender;
            // set idex of token in staker's wallet
            tokenIdToStakerIndex[tokenId]=stakerToIds[msg.sender].length;
            // push the token to staker's wallet
            stakerToIds[msg.sender].push(tokenId);
            // move the CS token to the contract
            cryptoshackContract.transferFrom(msg.sender, address(this), tokenId);
        }
    }