/* eslint-disable @typescript-eslint/no-explicit-any */
import { Context, NewTx, getMethodArguments, isSelfCall } from '@coinweb/contract-kit';

import { context, getRawContext, handleContext } from '../context';
import { execLoop, setNextExec, stopExecution } from '../runtime';
import { pushResolvedOp } from '../runtime/resolvedOps';

import { constructTx } from './constructTx';

export const executor = (method: (...args: any[]) => Promise<void>) => {
  return async (ctx: Context): Promise<NewTx[]> => {
    console.log('executor-start >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
    const shouldRestart = handleContext(ctx);
    pushResolvedOp(context.ops);

    if (getMethodArguments(getRawContext()).length > 2 && !isSelfCall(ctx)) {
      throw new Error('Wrong contract call, check the call arguments');
    }

    if (shouldRestart) {
      console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-finish-restart');
      return constructTx(false);
    }

    //@ts-expect-error
    // eslint-disable-next-line @typescript-eslint/no-unsafe-call
    os.setTimeout(() => {
      stopExecution();
    }, 0);

    try {
      setNextExec(() => method(...context.initialArgs));
      const isFullyExecuted = await execLoop();
      console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-finish-end');
      return constructTx(isFullyExecuted);
    } catch (error) {
      console.log((error as Error).message);
      console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-error');
      throw error;
    }
  };
};
