import {
  credentialToAddress,
  credentialToRewardAddress,
  fromHex,
  fromText,
  LucidEvolution,
  validatorToScriptHash,
} from '@lucid-evolution/lucid';
import {
  PythStateDatum,
  serialisePythStateDatum,
} from '../../src/contracts/pyth-feed/types';
import { alwaysSucceedValidator } from '../always-succeed/script';
import { runAndAwaitTxBuilder } from '../test-helpers';
import { AssetClass, mkAssetsOf } from '@3rd-eye-labs/cardano-offchain-common';
import { mintOneTimeToken } from '../../src';

export const TEST_TRUSTED_SIGNER_PRIV_KEY =
  'a8e6c4d187e6247719cf45112917094c6973d2cf5a5f2e9f3a6802543e523239';
export const TEST_TRUSTED_SIGNER_PUB_KEY =
  '4a50d7c3d16b2be5c16ba996109a455a34cce08a81b3e15b86ef407e2f72e71f';

// For the purpose of testing Pyth in an emulated environment, we need to initialize a Pyth State NFT
// This NFT will be sent to an always succeeds validator that will have the "Pyth State" datum
// The important part is that the Pyth State includes an always succeeds withdraw script and a
// trusted signer that we can use to validate the Pyth Messages we generate.
export async function initPyth(lucid: LucidEvolution): Promise<AssetClass> {
  const pythStateName = fromText('Pyth State');
  const pythStatePolicyId = await mintOneTimeToken(lucid, pythStateName, 1n);
  const pythStateAsset = {
    currencySymbol: fromHex(pythStatePolicyId),
    tokenName: fromHex(pythStateName),
  };

  const alwaysSucceedsValidatorHash = validatorToScriptHash(
    alwaysSucceedValidator,
  );
  const pythStateDatum: PythStateDatum = {
    // The governance doesn't matter for the purpose of testing, so we can use any values
    governance: {
      wormhole: fromHex(''),
      emitterChain: 0n,
      emitterAddress: fromHex(''),
      seenSequence: 0n,
    },
    trustedSigners: new Map([
      [
        fromHex(TEST_TRUSTED_SIGNER_PUB_KEY),
        {
          lower_bound: {
            bound_type: {
              _tag: 'NegativeInfinity',
            },
            is_inclusive: true,
          },
          upper_bound: {
            bound_type: {
              _tag: 'PositiveInfinity',
            },
            is_inclusive: true,
          },
        },
      ],
    ]),
    deprecatedWithdrawScripts: new Map(),
    // For the purpose of testing, we use the always succeeds validator to validate the Pyth Messages.
    // This means the message signature checking will always succeed for the purpose of emulation testing.
    withdraw_script: fromHex(alwaysSucceedsValidatorHash),
  };

  await runAndAwaitTxBuilder(
    lucid,
    lucid.newTx().pay.ToContract(
      credentialToAddress(lucid.config().network!, {
        hash: validatorToScriptHash(alwaysSucceedValidator),
        type: 'Script',
      }),
      { kind: 'inline', value: serialisePythStateDatum(pythStateDatum) },
      mkAssetsOf(pythStateAsset, 1n),
      alwaysSucceedValidator,
    ),
  );

  // Register the stake key for always succeeds validator.
  await runAndAwaitTxBuilder(
    lucid,
    lucid.newTx().register.Stake(
      credentialToRewardAddress(lucid.config().network!, {
        hash: validatorToScriptHash(alwaysSucceedValidator),
        type: 'Script',
      }),
    ),
  );

  return pythStateAsset;
}
