contract OwnixNFT is IOwnixERC1155, ERC1155Burnable, Ownable {
  uint256 private nextTokenId = 1;

  mapping(string => uint256) private ipfsHashToTokenId;
  mapping(uint256 => string) private tokenIdToIpfsHash;
  mapping(uint256 => address) private firstTimeOwner;
  address public marketAddress;

  event MarketAddressChanged(address marketAddress);
  event UriChanged(string uri);

  constructor() ERC1155("") {
  }

  /**
   * @dev mint0 new nft and approve to market
   *
   * @param _ipfsHash The IPFS hash
   * @param _amount the nft amount to mint
   */
  function mintAndApproveMarket(string memory _ipfsHash, uint256 _amount)
    external
    returns (uint256)
  {
    require(_amount > 0, "Amount must be greater then zero");
    require(ipfsHashToTokenId[_ipfsHash] == 0, "IPFS Hash already exists");

     uint256 tokenId = nextTokenId++;

    if (!isApprovedForAll(msg.sender, marketAddress)) {
      setApprovalForAll(marketAddress, true);
    }

    ipfsHashToTokenId[_ipfsHash] = tokenId;
    tokenIdToIpfsHash[tokenId] = _ipfsHash;

    firstTimeOwner[tokenId] = msg.sender;

    _mint(msg.sender, tokenId, _amount, "");

    return tokenId;
  }

  /**
   * @dev admin function to set new market address.
   *
   * @param _marketAddress address the new market to assign
   */
  function changeMarketAddress(address _marketAddress)
    external
    onlyOwner
  {
    require(
      _marketAddress != address(0),
      "address can't be the zero address"
    );

    marketAddress = _marketAddress;
    emit MarketAddressChanged(_marketAddress);
  }

  /**
   * @dev admin function to set new uri.
   *
   * @param _newUri the new uri
   */
  function setURI(string memory _newUri) external onlyOwner {
    _setURI(_newUri);
    emit UriChanged(_newUri);
  }

  /**
   * Read APIs
   */

  function uri(uint256 _id)
    public
    view
    virtual
    override(ERC1155)
    returns (string memory)
  {
    return string(abi.encodePacked(ERC1155.uri(_id), tokenIdToIpfsHash[_id], "/metadata.json"));
  }

  /**
   * @dev Get first time owner 
   * @param _tokenId - uint256 of the token id
   * @return owner address
   */
  function getFirstTimeOwner(uint256 _tokenId) override external view returns (address)  {
    return firstTimeOwner[_tokenId];
  }

    /**
   * @dev Get the next token Id
   * @return The next token id
   */
  function getNextTokenId()  external view returns (uint256)  {
    return nextTokenId;
  }
}
function uri(uint256 _id)
  public
  view
  virtual
  override(ERC1155)
  returns (string memory)
{
  return string(abi.encodePacked(ERC1155.uri(_id), tokenIdToIpfsHash[_id], "/metadata.json"));
}

/**
 * Read APIs
 */