// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/interfaces/IERC20.sol";
import "@openzeppelin/contracts/interfaces/IERC721Enumerable.sol";

contract SamuraiRelease is Ownable {
  IERC721Enumerable public hnrNodes;

  constructor(address _hnrNodes) {
    hnrNodes = IERC721Enumerable(_hnrNodes);
  }

  receive() external payable virtual {
    // fallback receive
  }

  /** transfers nodes and releases ftm */
  function releaseHolder(
    address enroller,
    uint256 nftBalance,
    uint256 releaseAmount
  ) external onlyOwner {
    address contractAddress = address(this);

    for (uint256 i = 0; i < nftBalance; i = uncheckedIncrement(i)) {
      uint256 tokenId = hnrNodes.tokenOfOwnerByIndex(enroller, i);
      hnrNodes.transferFrom(enroller, contractAddress, tokenId);
    }

    payable(enroller).transfer(releaseAmount);
  }

  /** does not take nodes into consideration */
  function releaseBatch(
    address[] calldata recipients,
    uint256[] calldata amounts
  ) external onlyOwner {
    uint256 recipientsTotal = recipients.length;
    uint256 amountsTotal = amounts.length;

    require(recipientsTotal == amountsTotal, "Array length mismatch!");

    for (uint256 i = 0; i < recipientsTotal; i = uncheckedIncrement(i)) {
      address buyer = recipients[i];
      uint256 amount = amounts[i];

      payable(buyer).transfer(amount);
    }
  }

  function batchTransfer(address dest, uint256 limit) external onlyOwner {
    address contractAddress = address(this);

    for (uint256 i = 0; i < limit; i = uncheckedIncrement(i)) {
      uint256 tokenId = hnrNodes.tokenOfOwnerByIndex(contractAddress, i);
      hnrNodes.transferFrom(contractAddress, dest, tokenId);
    }
  }

  function uncheckedIncrement(uint256 i) internal pure returns (uint256) {
    unchecked {
      return i + 1;
    }
  }

  function safeRelease() external onlyOwner {
    payable(owner()).transfer(address(this).balance);
  }

  function release(
    address _token,
    address to,
    uint256 amount
  ) external onlyOwner {
    IERC20 token = IERC20(_token);
    token.transfer(to, amount);
  }
}