// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;
import '@openzeppelin/contracts/utils/Strings.sol';
import '@abf-monorepo/protocol/contracts/libraries/BytesUtils.sol';

library NftMetadataUtils {
  string constant JSON_DELIMITER = ',';
  string constant VALUE_KEY = 'value';
  string constant TRAIT_TYPE_KEY = 'trait_type';
  string constant MAX_VALUE_KEY = 'max_value';
  string constant DISPLAY_TYPE_KEY = 'display_type';

  string constant BOOST_NUMBER_DISPLAY_TYPE = 'boost_number';
  string constant BOOST_PERCENTAGE_DISPLAY_TYPE = 'boost_percentage';
  string constant NUMBER_DISPLAY_TYPE = 'number';
  string constant DATE_DISPLAY_TYPE = 'date';

  function object(string[] memory content) public pure returns (string memory) {
    return string(abi.encodePacked('{', delimit(content), '}'));
  }

  function array(string[] memory content) public pure returns (string memory) {
    return string(abi.encodePacked('[', delimit(content), ']'));
  }

  function keyValue(string memory key, string memory value)
    public
    pure
    returns (string memory)
  {
    return string(abi.encodePacked('"', key, '":', value));
  }

  function stringWrap(string memory value) public pure returns (string memory) {
    return string(abi.encodePacked('"', value, '"'));
  }

  function delimit(string[] memory values) public pure returns (string memory) {
    bytes memory delimitedValues = '';
    for (uint256 i = 0; i < values.length; ++i) {
      delimitedValues = abi.encodePacked(
        delimitedValues,
        i == 0 ? '' : JSON_DELIMITER,
        values[i]
      );
    }
    return string(delimitedValues);
  }

  function getBaseAttributeObject(
    string memory traitType,
    string memory value,
    string memory extra
  ) public pure returns (string memory) {
    string[] memory components = new string[](3);
    components[0] = keyValue(VALUE_KEY, value);
    components[1] = keyValue(TRAIT_TYPE_KEY, stringWrap(traitType));
    components[2] = extra;

    return object(components);
  }

  function getAttributeObject(string memory traitType, string memory value)
    public
    pure
    returns (string memory)
  {
    return getBaseAttributeObject(traitType, value, '');
  }

  function getAttributeObjectWithMaxValue(
    string memory traitType,
    string memory value,
    string memory maxValue
  ) public pure returns (string memory) {
    return
      getBaseAttributeObject(
        traitType,
        value,
        keyValue(MAX_VALUE_KEY, maxValue)
      );
  }

  function getAttributeObjectWithDisplayType(
    string memory traitType,
    string memory value,
    string memory displayType
  ) public pure returns (string memory) {
    return
      getBaseAttributeObject(
        traitType,
        value,
        keyValue(DISPLAY_TYPE_KEY, displayType)
      );
  }

  function getAttributeObjectWithDisplayTypeAndMaxValue(
    string memory traitType,
    string memory value,
    string memory displayType,
    string memory maxValue
  ) public pure returns (string memory) {
    string[] memory components = new string[](2);
    components[0] = keyValue(DISPLAY_TYPE_KEY, stringWrap(displayType));
    components[1] = keyValue(MAX_VALUE_KEY, maxValue);
    return getBaseAttributeObject(traitType, value, delimit(components));
  }
}
[{"inputs":[{"internalType":"address","name":"_rce","type":"address"},{"internalType":"address","name":"_compositingRenderer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"compositingRenderer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"encodedAttributeIndexes","type":"uint16[]"}],"name":"decodeAttributeIndexesWithLiveServiceData","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint16[]","name":"attributeIndexes","type":"uint16[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"seed","type":"bytes"},{"internalType":"uint16[]","name":"attributeIndexes","type":"uint16[]"}],"name":"encodeAttributeIndexesWithLiveServiceData","outputs":[{"internalType":"uint16[]","name":"encodedAttributeIndexes","type":"uint16[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"attributeIndexes","type":"uint16[]"}],"name":"getAttributesJSON","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rarityMultiplier","type":"uint256"},{"internalType":"bytes","name":"seed","type":"bytes"}],"name":"getRarity","outputs":[{"internalType":"uint256[]","name":"layerIndexes","type":"uint256[]"},{"internalType":"uint16[]","name":"attributeIndexes","type":"uint16[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"attributeIndexes","type":"uint16[]"}],"name":"getRender","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"attributeIndexes","type":"uint16[]"}],"name":"getRenderRaw","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"encodedAttributeIndexes","type":"uint16[]"}],"name":"getRendererProps","outputs":[{"internalType":"address[]","name":"renderers","type":"address[]"},{"internalType":"bytes[]","name":"rendererProps","type":"bytes[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxAttributeRenderersIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGenericRenderersIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxVisualLayersIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rce","outputs":[{"internalType":"contract RarityCompositingEngine","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"internalType":"address[]","name":"renderers","type":"address[]"}],"name":"setAttributeMetadataRenderers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_compositingRenderer","type":"address"}],"name":"setCompositingRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"internalType":"address[]","name":"renderers","type":"address[]"}],"name":"setGenericMetadataRenderers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxAttributeRenderersIndex","type":"uint256"}],"name":"setMaxAttributeRenderersIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGenericRenderersIndex","type":"uint256"}],"name":"setMaxGenericRenderersIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxVisualLayersIndex","type":"uint256"}],"name":"setMaxVisualLayersIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"internalType":"uint256[]","name":"attributeIndexes","type":"uint256[]"}],"name":"setVisualLayerIndexRemap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"internalType":"address[]","name":"renderers","type":"address[]"}],"name":"setVisualLayerRenderers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]