import type { OnboardingPrepareResponse, PrepareTransferResponse } from "../../types/gateway";
import { PrepareTransactionResponse } from "../../types/onboard";
import { CantonSignature, CantonSigner } from "../../types/signer";
import { splitTransaction } from "@ledgerhq/hw-app-canton";

/**
 * Sign a Canton transaction - handles both prepared transactions and untyped versioned messages
 */

export async function signTransaction(
  signer: CantonSigner,
  derivationPath: string,
  transactionData: PrepareTransferResponse | PrepareTransactionResponse | OnboardingPrepareResponse,
): Promise<CantonSignature> {
  let signPayload;

  // OnboardingPrepareResponse — sign topology transactions as untyped versioned messages
  if ("transactions" in transactionData && transactionData.transactions) {
    const challenge = getTransactionChallenge(transactionData);
    const { transactions } = transactionData;

    signPayload = {
      transactions: [
        transactions.namespace_transaction.serialized,
        transactions.party_to_key_transaction.serialized,
        transactions.party_to_participant_transaction.serialized,
      ],
      ...(challenge && { challenge }),
    };
  } else {
    // PrepareTransferResponse / PrepareTransactionResponse (.json) or raw JSON from craftTransaction
    const rawTransactionData = "json" in transactionData ? transactionData.json : transactionData;

    signPayload = splitTransaction(rawTransactionData);
  }

  const signature = await signer.signTransaction(derivationPath, signPayload);

  if (!signature?.signature) {
    throw new Error("Device returned empty signature");
  }

  return signature;
}

const getTransactionChallenge = ({
  challenge_nonce,
  challenge_deadline,
}: OnboardingPrepareResponse) => {
  if (!challenge_nonce || !challenge_deadline) {
    return undefined;
  }

  try {
    const deadlineHex = Buffer.alloc(8);
    deadlineHex.writeBigInt64BE(BigInt(challenge_deadline), 0);

    // Format: [length (1B) = 0x18][challenge (16 bytes)][deadline (8 bytes)]
    return "18" + challenge_nonce.toLowerCase() + deadlineHex.toString("hex");
  } catch {
    return undefined;
  }
};
