import assert from "assert";

import { translateError } from "@project-serum/anchor";
import {
	ConfirmOptions,
	Connection,
	Signer,
	Transaction,
	TransactionSignature,
	VersionedTransaction,
} from "@solana/web3.js";

export class SolmashWhitelistPayload {
	constructor(
		private readonly _connection: Connection,
		private readonly _signTransaction: <T extends Transaction | VersionedTransaction>(
			transaction: T,
		) => Promise<T>,
		private readonly _errors: Map<number, string>,
		readonly transaction: Transaction,
		readonly signers: Signer[],
	) {}

	async execute(options?: ConfirmOptions): Promise<TransactionSignature> {
		assert(this.transaction.recentBlockhash, "Blockhash is missing in transaction!");
		assert(
			this.transaction.lastValidBlockHeight,
			"LastValidBlockHeight is missing in transaction!",
		);

		const blockhash = this.transaction.recentBlockhash;
		const lastValidBlockHeight = this.transaction.lastValidBlockHeight;

		if (this.signers.length > 0) {
			this.transaction.partialSign(...this.signers);
		}

		const signed = await this._signTransaction(this.transaction);

		try {
			const signature = await this._connection.sendRawTransaction(signed.serialize(), options);
			console.debug("signatue: %s", signature);

			const response = await this._connection.confirmTransaction(
				{
					signature,
					blockhash,
					lastValidBlockHeight,
				},
				options?.commitment,
			);

			if (response.value.err) {
				throw new Error("Failed to confirm transaction: " + response.value.err.toString());
			}

			return signature;
		} catch (err: any) {
			const translatedError = translateError(err, this._errors);

			if (translatedError) {
				// assert(translatedError instanceof Error, "Translated error is not instanceof Error.");
				if (!(translatedError instanceof Error)) {
					console.log("translatedError:", translatedError);
					throw new Error("Unknown error occured. Please try again.");
				}
				throw translatedError;
			}

			console.debug("Throwing error as it is.");
			throw err;
		}
	}
}
