// usage:
// $ npm install graphql-request table ts-node
// $ npm install -D @types/table
// $ ts-node fields_tvl.ts

import { request, gql } from "graphql-request";
import { table } from "table";

const ASTRO_GENERATOR = "terra1zgrx9jjqrfye8swykfgmd6hpde60j0nszzupp9";
const MARS_RED_BANK = "terra19dtgj9j5j7kyf3pmejqv8vzfpxtejaypgzkz5u";

const graphUrl = "https://mantle.terra.dev";

type PoolResponse = {
  assets: {
    info: { token: { contract_addr: string } } | { native_token: { denom: string } };
    amount: string;
  }[];
  total_share: string;
};

type BondResponse = string;

interface DebtResponse {
  amount: string;
}

async function calculateStrategyTvl(strategy: string, pair: string, lpToken: string) {
  const query = gql`
    query fieldsTvl(
      $poolQuery: String!,
      $bondQuery: String!,
      $debtQuery: String!,
    ) {
      poolResponse: WasmContractsContractAddressStore(
        ContractAddress: "${pair}",
        QueryMsg: $poolQuery
      ) {
        Result
      },
      bondResponse: WasmContractsContractAddressStore(
        ContractAddress: "${ASTRO_GENERATOR}",
        QueryMsg: $bondQuery
      ) {
        Result
      },
      debtResponse: WasmContractsContractAddressStore(
        ContractAddress: "${MARS_RED_BANK}",
        QueryMsg: $debtQuery
      ) {
        Result
      }
    }
  `;

  const results = await request(graphUrl, query, {
    poolQuery: JSON.stringify({
      pool: {},
    }),
    bondQuery: JSON.stringify({
      deposit: {
        lp_token: lpToken,
        user: strategy,
      },
    }),
    debtQuery: JSON.stringify({
      user_asset_debt: {
        user_address: strategy,
        asset: {
          native: {
            denom: "uusd",
          },
        },
      },
    }),
  });

  const poolResponse: PoolResponse = JSON.parse(results.poolResponse.Result);
  const bondResponse: BondResponse = JSON.parse(results.bondResponse.Result);
  const debtResponse: DebtResponse = JSON.parse(results.debtResponse.Result);

  const assetDepth = parseInt(
    poolResponse.assets.find(
      (asset) => JSON.stringify(asset.info) != '{"native_token":{"denom":"uusd"}}',
    )!.amount,
  );
  const uusdDepth = parseInt(
    poolResponse.assets.find(
      (asset) => JSON.stringify(asset.info) == '{"native_token":{"denom":"uusd"}}',
    )!.amount,
  );

  const bondedShares = parseInt(bondResponse);
  const totalShares = parseInt(poolResponse.total_share);

  const uusdBorrowed = parseInt(debtResponse.amount);

  const assetBonded = (assetDepth * bondedShares) / totalShares;
  const uusdBonded = (uusdDepth * bondedShares) / totalShares;
  const assetPrice = uusdDepth / assetDepth;

  const bondValue = (assetBonded * assetPrice + uusdBonded * 1) / 1e6;
  const debtValue = (uusdBorrowed * 1) / 1e6;

  return { bondValue, debtValue };
}

const formatInteger = (x: number) => x.toFixed(0).replace(/\B(?=(\d{3})+(?!\d))/g, ",");

const formatPercentage = (x: number) => (100 * x).toFixed(1) + "%";

(async function () {
  const lunaStrategyTvl = await calculateStrategyTvl(
    "terra1kztywx50wv38r58unxj9p6k3pgr2ux6w5x68md", // Fields of Mars LUNA-UST strategy
    "terra1m6ywlgn6wrjuagcmmezzz2a029gtldhey5k552", // Astroport LUNA-UST pair
    "terra1m24f7k4g66gnh9f7uncp32p722v0kyt3q4l3u5", // Astroport LUNA-UST LP token
  );
  const ancStrategyTvl = await calculateStrategyTvl(
    "terra1vapq79y9cqghqny7zt72g4qukndz282uvqwtz6", // Fields of Mars ANC-UST strategy
    "terra1qr2k6yjjd5p2kaewqvg93ag74k6gyjr7re37fs", // Astroport ANC-UST pair
    "terra1wmaty65yt7mjw6fjfymkd9zsm6atsq82d9arcd", // Astroport ANC-UST LP token
  );
  const mirStrategyTvl = await calculateStrategyTvl(
    "terra12dq4wmfcsnz6ycep6ek4umtuaj6luhfp256hyu", // Fields of Mars MIR-UST strategy
    "terra143xxfw5xf62d5m32k3t4eu9s82ccw80lcprzl9", // Astroport MIR-UST pair
    "terra17trxzqjetl0q6xxep0s2w743dhw2cay0x47puc", // Astroport MIR-UST LP token
  );

  console.log(
    table(
      [
        ["strategy", "asset_value", "debt_value", "overall_ltv"],
        [
          "LUNA-UST",
          formatInteger(lunaStrategyTvl.bondValue),
          formatInteger(lunaStrategyTvl.debtValue),
          formatPercentage(lunaStrategyTvl.debtValue / lunaStrategyTvl.bondValue),
        ],
        [
          "ANC-UST",
          formatInteger(ancStrategyTvl.bondValue),
          formatInteger(ancStrategyTvl.debtValue),
          formatPercentage(ancStrategyTvl.debtValue / ancStrategyTvl.bondValue),
        ],
        [
          "MIR-UST",
          formatInteger(mirStrategyTvl.bondValue),
          formatInteger(mirStrategyTvl.debtValue),
          formatPercentage(mirStrategyTvl.debtValue / mirStrategyTvl.bondValue),
        ],
        [
          "total",
          formatInteger(lunaStrategyTvl.bondValue + ancStrategyTvl.bondValue + mirStrategyTvl.bondValue),
          formatInteger(lunaStrategyTvl.debtValue + ancStrategyTvl.debtValue + mirStrategyTvl.debtValue),
          "n/a"
        ]
      ],
      {
        drawHorizontalLine: (lineIndex, rowCount) => {
          return lineIndex === 0 || lineIndex === 1 || lineIndex === rowCount - 1 || lineIndex === rowCount;
        },
        columns: [
          { alignment: "left" },
          { alignment: "right" },
          { alignment: "right" },
          { alignment: "right" },
        ],
      },
    ),
  );
})();