import { constructContinueTx, NewTx, passCwebFrom, sendCwebInterface } from '@coinweb/contract-kit';

import { Task } from '../../../types';
import { context, getRawContext } from '../../context';

import { prepareInThreadTxs } from './prepareInThreadTxs';
import { prepareOutThreadTxs } from './prepareOutThreadTxs';
import { splitTasks } from './splitTasks';

export const prepareTx = ({
  awaitedTasks,
  isFullyExecuted,
  txFee,
  callsCount,
}: {
  awaitedTasks: Task[];
  isFullyExecuted: boolean;
  txFee: bigint;
  callsCount?: number;
}): { txs: NewTx[]; calls: number; txFee: bigint } => {
  if (!awaitedTasks.length) {
    if (context.isChild) {
      return { txs: [], calls: 0, txFee: 0n };
    }

    const { constructSendCweb } = sendCwebInterface();
    const { availableCweb, takeOps, storedCweb } = context.funds;
    const { user } = context;

    const fee = BigInt(takeOps.length) * 100n + 3000n; //TODO: Remove magic numbers
    const restOfCweb = availableCweb + storedCweb - fee;

    const txs =
      restOfCweb > 0n
        ? [
            constructContinueTx(getRawContext(), [
              passCwebFrom(context.issuer, availableCweb),
              ...takeOps,
              ...constructSendCweb(restOfCweb, user, null),
            ]),
          ]
        : [];

    return { txs, calls: 0, txFee: fee };
  }

  const { inThreadOps, outThreadOps } = splitTasks(awaitedTasks, isFullyExecuted);

  const { availableCweb } = context.funds;

  const cwebPerCall = (availableCweb - txFee) / BigInt(callsCount || 1);

  const {
    txs: outThreadTxs,
    calls: outThreadCallsPrepared,
    txFee: outThreadFee,
  } = prepareOutThreadTxs({ ops: outThreadOps, cwebPerCall });

  const {
    txs: inThreadTxs,
    calls: inThreadCallsPrepared,
    txFee: inThreadFee,
  } = prepareInThreadTxs({
    ops: inThreadOps,
    cwebPerCall,
    outThreadTasksCount: outThreadOps.length,
    outThreadFee,
  });

  return {
    txs: [...inThreadTxs, ...outThreadTxs],
    calls: inThreadCallsPrepared + outThreadCallsPrepared,
    txFee: inThreadFee + outThreadFee,
  };
};
