import { AssetClass, matchSingle } from '@3rd-eye-labs/cardano-offchain-common';
import {
  LucidEvolution,
  ScriptHash,
  toHex,
  UTxO,
} from '@lucid-evolution/lucid';
import {
  parseStableswapOrderDatum,
  StableswapOrderDatum,
} from '../../src/contracts/stableswap/types-new';
import { createScriptAddress } from '../../src';
import { array as A, function as F, option as O } from 'fp-ts';

export async function findSingleStableswapOrder(
  lucid: LucidEvolution,
  stableswapScriptHash: ScriptHash,
  iassetName: string,
  collateralAsset: AssetClass,
): Promise<{ utxo: UTxO; datum: StableswapOrderDatum }> {
  const cdpUtxos = await lucid.utxosAt(
    createScriptAddress(lucid.config().network!, stableswapScriptHash),
  );

  return matchSingle(
    F.pipe(
      cdpUtxos.map((utxo) =>
        F.pipe(
          O.fromNullable(utxo.datum),
          O.flatMap(parseStableswapOrderDatum),
          O.flatMap((datum) => {
            if (
              toHex(datum.iasset) === iassetName &&
              toHex(datum.collateralAsset.currencySymbol) ===
                toHex(collateralAsset.currencySymbol) &&
              toHex(datum.collateralAsset.tokenName) ===
                toHex(collateralAsset.tokenName)
            ) {
              return O.some({ utxo, datum: datum });
            } else {
              return O.none;
            }
          }),
        ),
      ),
      A.compact,
    ),
    (res) =>
      new Error(
        'Expected a single stableswap order UTXO.: ' + JSON.stringify(res),
      ),
  );
}

export async function findStableswapOrders(
  lucid: LucidEvolution,
  stableswapScriptHash: ScriptHash,
  iassetName: string,
  collateralAsset: AssetClass,
): Promise<{ utxo: UTxO; datum: StableswapOrderDatum }[]> {
  const cdpUtxos = await lucid.utxosAt(
    createScriptAddress(lucid.config().network!, stableswapScriptHash),
  );

  const orders = F.pipe(
    cdpUtxos.map((utxo) =>
      F.pipe(
        O.fromNullable(utxo.datum),
        O.flatMap(parseStableswapOrderDatum),
        O.flatMap((datum) => {
          if (
            toHex(datum.iasset) === iassetName &&
            toHex(datum.collateralAsset.currencySymbol) ===
              toHex(collateralAsset.currencySymbol) &&
            toHex(datum.collateralAsset.tokenName) ===
              toHex(collateralAsset.tokenName)
          ) {
            return O.some({ utxo, datum: datum });
          } else {
            return O.none;
          }
        }),
      ),
    ),
    A.compact,
  );

  return orders;
}
