import { Context, extractUser, getMethodArguments } from '@coinweb/contract-kit';
import { getCallParameters, getContractIssuer } from 'lib/onchain';

import { ExecutorMethodArgs } from '../../types';
import { uuid } from '../utils';

import { extractFunds } from './extractFunds';
import { extractOps } from './extractOps';

let rawContext: Context | null = null;

export const setRawContext = (ctx: Context) => {
  rawContext = ctx;
};

export const getRawContext = () => {
  if (!rawContext) {
    throw new Error('Context not set');
  }

  return rawContext;
};

export const getMethodArgs = () => {
  return getMethodArguments(getRawContext()) as [methodName: string, ...ExecutorMethodArgs];
};

let thisId: string | undefined;

export const context = {
  get isChild() {
    return !!getMethodArgs()[5];
  },
  get thisId() {
    thisId = thisId ?? getMethodArgs()[4] ?? uuid();
    return thisId;
  },
  get parentId() {
    return getMethodArgs()[5];
  },
  get ops() {
    console.log('Parse ops in context');

    const previousOps = getMethodArgs()[2] ?? [];
    const { extractedOps } = extractOps();

    const allResolvedOps = [...previousOps, ...extractedOps];

    console.log('new ops >>>', JSON.stringify(extractedOps));

    return allResolvedOps;
  },
  get funds() {
    const { availableCweb } = getCallParameters(getRawContext());

    const { amount: storedCweb, takeOps } = extractFunds();

    console.log('Available Cweb: ', availableCweb);
    console.log('Stored Cweb: ', storedCweb);
    console.log('Take Ops: ', takeOps);

    return {
      availableCweb,
      storedCweb,
      takeOps,
    };
  },
  get methodName() {
    return getMethodArguments(getRawContext())[0] as string;
  },
  get initialArgs() {
    return getMethodArgs()[1] ?? [];
  },
  get user() {
    const { authInfo } = getCallParameters(getRawContext());
    const provided = getMethodArgs()[3];

    const user = (authInfo && extractUser(authInfo)) ?? provided;

    if (!user) {
      throw new Error('User not found');
    }

    return user;
  },
  get issuer() {
    return getContractIssuer(getRawContext());
  },
  get parentTxId() {
    return getRawContext().call.txid;
  },
  get needSaveResult() {
    return getMethodArgs()[6] ?? false;
  },
};
