import type { Transaction } from "./types";
import { createVarint } from "./varint";

/**
  @example
const tx1 = btc.splitTransaction("01000000014ea60aeac5252c14291d428915bd7ccd1bfc4af009f4d4dc57ae597ed0420b71010000008a47304402201f36a12c240dbf9e566bc04321050b1984cd6eaf6caee8f02bb0bfec08e3354b022012ee2aeadcbbfd1e92959f57c15c1c6debb757b798451b104665aa3010569b49014104090b15bde569386734abf2a2b99f9ca6a50656627e77de663ca7325702769986cf26cc9dd7fdea0af432c8e2becc867c932e1b9dd742f2a108997c2252e2bdebffffffff0281b72e00000000001976a91472a5d75c8d2d0565b656a5232703b167d50d5a2b88aca0860100000000001976a9144533f5fb9b4817f713c48f0bfe96b9f50c476c9b88ac00000000");
const outputScript = btc.serializeTransactionOutputs(tx1).toString('hex');
  */
export function serializeTransactionOutputs({ outputs }: Transaction): Buffer {
  let outputBuffer = Buffer.alloc(0);

  if (typeof outputs !== "undefined") {
    outputBuffer = Buffer.concat([outputBuffer, createVarint(outputs.length)]);
    outputs.forEach(output => {
      outputBuffer = Buffer.concat([
        outputBuffer,
        output.amount,
        createVarint(output.script.length),
        output.script,
      ]);
    });
  }

  return outputBuffer;
}
export function serializeTransaction(
  transaction: Transaction,
  skipWitness: boolean,
  timestamp?: Buffer,
  additionals: string[] = [],
) {
  const isDecred = additionals.includes("decred");
  const isZcash = additionals.includes("zcash");
  const isBech32 = additionals.includes("bech32");
  let inputBuffer = Buffer.alloc(0);
  const useWitness = typeof transaction["witness"] != "undefined" && !skipWitness;
  transaction.inputs.forEach(input => {
    inputBuffer =
      isDecred || isBech32
        ? Buffer.concat([
            inputBuffer,
            input.prevout,
            Buffer.from([0x00]), //tree
            input.sequence,
          ])
        : Buffer.concat([
            inputBuffer,
            input.prevout,
            createVarint(input.script.length),
            input.script,
            input.sequence,
          ]);
  });
  let outputBuffer = serializeTransactionOutputs(transaction);

  if (typeof transaction.outputs !== "undefined" && typeof transaction.locktime !== "undefined") {
    outputBuffer = Buffer.concat([
      outputBuffer,
      (useWitness && transaction.witness) || Buffer.alloc(0),
      transaction.locktime,
      transaction.nExpiryHeight || Buffer.alloc(0),
      transaction.extraData || Buffer.alloc(0),
    ]);
  }
  // from to https://zips.z.cash/zip-0225, zcash is different with other coins, the lock_time and nExpiryHeight fields are before the inputs and outputs
  if (isZcash) {
    return Buffer.concat([
      transaction.version,
      transaction.nVersionGroupId || Buffer.alloc(0),
      transaction.consensusBranchId || Buffer.from([0x00, 0x00, 0x00, 0x00]),
      transaction.locktime || Buffer.from([0x00, 0x00, 0x00, 0x00]),
      transaction.nExpiryHeight || Buffer.from([0x00, 0x00, 0x00, 0x00]),
      useWitness ? Buffer.from("0001", "hex") : Buffer.alloc(0),
      createVarint(transaction.inputs.length),
      inputBuffer,
      outputBuffer,
    ]);
  }
  return Buffer.concat([
    transaction.version,
    timestamp ? timestamp : Buffer.alloc(0),
    transaction.nVersionGroupId || Buffer.alloc(0),
    useWitness ? Buffer.from("0001", "hex") : Buffer.alloc(0),
    createVarint(transaction.inputs.length),
    inputBuffer,
    outputBuffer,
  ]);
}
