import {
  Credential,
  fromText,
  LucidEvolution,
  toHex,
} from '@lucid-evolution/lucid';
import { createScriptAddress } from '../../src/utils/lucid-utils';
import { RobOutput, parseRobDatum } from '../../src/contracts/rob/types-new';
import { option as O, array as A, function as F } from 'fp-ts';
import { SystemParams } from '../../src';
import { LucidContext } from '../test-helpers';
import { matchSingle } from '@3rd-eye-labs/cardano-offchain-common';

/**
 * Beware, this shouldn't be used in production since it queries all the UTXOs
 * at an address and does the filtering in this function.
 */
export async function findRob(
  context: LucidContext,
  sysParams: SystemParams,
  owner: string,
  assetTokenName: string,
  stakeCredential?: Credential,
): Promise<RobOutput[]> {
  const network = context.lucid.config().network!;

  const robUtxos = await context.lucid.utxosAt(
    createScriptAddress(
      network,
      sysParams.validatorHashes.robHash,
      stakeCredential,
    ),
  );

  return F.pipe(
    robUtxos,
    A.map((utxo) =>
      F.pipe(
        O.fromNullable(utxo.datum),
        O.flatMap(parseRobDatum),
        O.flatMap((datum) => {
          if (
            toHex(datum.owner) == owner &&
            toHex(datum.iasset) == fromText(assetTokenName)
          ) {
            return O.some({ utxo, datum });
          } else return O.none;
        }),
      ),
    ),
    A.compact,
  );
}

export async function findSingleRob(
  context: LucidContext,
  sysParams: SystemParams,
  iasset: string,
  pkh: Credential,
): Promise<RobOutput> {
  return matchSingle(
    await findRob(context, sysParams, pkh.hash, iasset),
    (res) => new Error('Expected a single ROB UTXO.: ' + JSON.stringify(res)),
  );
}

export async function findAllRobs(
  lucid: LucidEvolution,
  sysParams: SystemParams,
  iasset: string,
): Promise<RobOutput[]> {
  const robUtxos = await lucid.utxosAt(
    createScriptAddress(
      lucid.config().network!,
      sysParams.validatorHashes.robHash,
    ),
  );

  return F.pipe(
    robUtxos.map((utxo) =>
      F.pipe(
        O.fromNullable(utxo.datum),
        O.flatMap(parseRobDatum),
        O.flatMap((datum) => {
          if (toHex(datum.iasset) === fromText(iasset)) {
            return O.some({ utxo, datum: datum });
          } else {
            return O.none;
          }
        }),
      ),
    ),
    A.compact,
  );
}
