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

import { context, getRawContext, setRawContext } from './context';
import { pushResolvedOp } from './promisifiedOps/resolved';
import { constructTx } from './utils';

let abortExecution: ((result: boolean) => void) | null = null;

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

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

    const execution = new Promise<boolean>((resolve, reject) => {
      abortExecution = resolve;

      method(...context.initialArgs).then(
        () => {
          console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-resolved');
          resolve(true);
        },
        (error) => {
          console.log(' <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<executor-rejected');
          console.log(error);
          reject(error);
        }
      );
    });

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

    try {
      const isFullyExecuted = await execution;
      return constructTx(isFullyExecuted);
    } catch (error) {
      console.log('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< executor-error');
      console.log((error as Error).message);
      throw error;
    }
  };
};

export const stopExecution = () => {
  console.log('stopExecution');
  abortExecution?.(false);
};
