import { beforeEach, describe, test } from 'vitest';
import {
  loadSystemParamsFromFile,
  mkCDPCreatorValidatorFromSP,
  mkCdpValidatorFromSP,
  mkCollectorValidatorFromSP,
  mkExecuteValidatorFromSP,
  mkRobValidatorFromSP,
  mkPollManagerValidatorFromSP,
  mkPollShardValidatorFromSP,
  mkVersionRegistryValidator,
} from '../src';
import { LucidContext } from './test-helpers';
import {
  Emulator,
  EmulatorAccount,
  Lucid,
  LucidEvolution,
  SpendingValidator,
  TxBuilder,
  credentialToAddress,
  fromHex,
  generateEmulatorAccount,
} from '@lucid-evolution/lucid';
import { benchmarkAndAwaitTx } from './utils/benchmark-utils';
import { mkGovValidatorFromSP } from '../src/contracts/gov/scripts';
import { mkStabilityPoolValidatorFromSP } from '../src/contracts/stability-pool/scripts';
import { mkStakingValidatorFromSP } from '../src/contracts/staking/scripts';
import { mkTreasuryValidatorFromSP } from '../src/contracts/treasury/scripts';
import { mkStableswapValidatorFromSP } from '../src/contracts/stableswap/scripts';
import { mkPythFeedValidator } from '../src/contracts/pyth-feed/scripts';
import { MAINNET_PROTOCOL_PARAMETERS } from './indigo-test-helpers';

const systemParams = loadSystemParamsFromFile(
  './tests/data/system-params.json',
);

type TestContext = LucidContext<{
  admin: EmulatorAccount;
}>;

describe('Script Size', () => {
  function initScriptRef(
    lucid: LucidEvolution,
    validator: SpendingValidator,
  ): TxBuilder {
    return lucid.newTx().pay.ToContract(
      credentialToAddress(lucid.config().network!, {
        hash: 'ea84d625650d066e1645e3e81d9c70a73f9ed837bd96dc49850ae744', // always fail validator hash
        type: 'Script',
      }),
      undefined,
      undefined,
      validator,
    );
  }

  beforeEach<TestContext>(async (context: TestContext) => {
    context.users = {
      admin: generateEmulatorAccount({
        lovelace: BigInt(100_000_000),
      }),
    };

    context.emulator = new Emulator(
      [context.users.admin],
      MAINNET_PROTOCOL_PARAMETERS,
    );
    context.lucid = await Lucid(context.emulator, 'Custom');
    context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase);
  });

  test('CDP Creator', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - CDP Creator',
      initScriptRef(
        context.lucid,
        mkCDPCreatorValidatorFromSP(systemParams.cdpCreatorParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('CDP', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - CDP',
      initScriptRef(
        context.lucid,
        mkCdpValidatorFromSP(systemParams.cdpParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Collector', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Collector',
      initScriptRef(
        context.lucid,
        mkCollectorValidatorFromSP(systemParams.collectorParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Execute', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Execute',
      initScriptRef(
        context.lucid,
        mkExecuteValidatorFromSP(systemParams.executeParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Gov', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Gov',
      initScriptRef(
        context.lucid,
        mkGovValidatorFromSP(systemParams.govParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('ROB', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - ROB',
      initScriptRef(
        context.lucid,
        mkRobValidatorFromSP(systemParams.robParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Poll Manager', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Poll Manager',
      initScriptRef(
        context.lucid,
        mkPollManagerValidatorFromSP(systemParams.pollManagerParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Poll Shard', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Poll Shard',
      initScriptRef(
        context.lucid,
        mkPollShardValidatorFromSP(systemParams.pollShardParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Pyth Feed', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Pyth Feed',
      initScriptRef(
        context.lucid,
        mkPythFeedValidator({
          config: { Value: { configuration: { priceFeedId: 0n } } },
          pythStatePolicyId: fromHex(''),
        }),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Stability Pool', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Stability Pool',
      initScriptRef(
        context.lucid,
        mkStabilityPoolValidatorFromSP(systemParams.stabilityPoolParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Stableswap', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Stableswap',
      initScriptRef(
        context.lucid,
        mkStableswapValidatorFromSP(systemParams.stableswapParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Staking', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Staking',
      initScriptRef(
        context.lucid,
        mkStakingValidatorFromSP(systemParams.stakingParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Treasury', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Treasury',
      initScriptRef(
        context.lucid,
        mkTreasuryValidatorFromSP(systemParams.treasuryParams),
      ),
      context.lucid,
      context.emulator,
    );
  });

  test('Version Registry', async (context: TestContext) => {
    await benchmarkAndAwaitTx(
      'Script Size - Version Registry',
      initScriptRef(context.lucid, mkVersionRegistryValidator()),
      context.lucid,
      context.emulator,
    );
  });
});
