import { VersionedTransaction } from '@solana/web3.js';

export const makeExternalRequest = async (apiDomain: string, endpoint: string, data: any) => {
  const response = await fetch(`${apiDomain}${endpoint}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(data),
  });

  if (!response.ok) {
    throw new Error(`External request failed: ${response.statusText}`);
  }

  return response.json();
};

export const makeExternalGetRequest = async (apiDomain: string, endpoint: string, params?: Record<string, string>) => {
  const url = new URL(`${apiDomain}${endpoint}`);
  if (params) {
    Object.entries(params).forEach(([key, value]) => {
      url.searchParams.append(key, value);
    });
  }

  const response = await fetch(url.toString(), {
    method: 'GET',
    headers: {
      'Content-Type': 'application/json',
    },
  });

  if (!response.ok) {
    throw new Error(`External request failed: ${response.statusText}`);
  }

  return response.json();
};

const safeSerialize = (data: any) => {
  return JSON.parse(JSON.stringify(data, (_key, value) => (typeof value === 'bigint' ? value.toString() : value)));
};

export const createExternalSigner = (
  apiDomain: string,
  externalSubOrgId: string,
  chainId: number,
  signWith?: string | null,
) => {
  return {
    account: signWith,
    writeContract: (data: any) => {
      // Attempt to safely serialize BigInt values to string
      const safeData = safeSerialize(data);
      return makeExternalRequest(apiDomain, '/api/turnkey/external-transaction', {
        orgId: externalSubOrgId,
        transactionData: safeData,
        type: 'writeContract',
        address: signWith || data.account,
        chainId,
      });
    },
    sendTransaction: (data: any) => {
      // Attempt to safely serialize BigInt values to string
      const safeData = safeSerialize(data);
      return makeExternalRequest(apiDomain, '/api/turnkey/external-transaction', {
        orgId: externalSubOrgId,
        transactionData: safeData,
        type: 'sendTransaction',
        address: signWith || data.account,
        chainId,
      });
    },
    signAllTransactions: (transactions: any, address: any) => {
      return makeExternalRequest(apiDomain, '/api/turnkey/external-transaction', {
        orgId: externalSubOrgId,
        transactions: transactions,
        address: address,
        type: 'signAllTransactions',
        chainId,
      });
    },
    addSignature: (transaction: VersionedTransaction, address: any) => {
      const serializedTransaction: Uint8Array<ArrayBufferLike> = transaction.serialize();

      // Convert the serialized Uint8Array to a base64 string
      const base64Transaction = Buffer.from(serializedTransaction).toString('base64');

      return makeExternalRequest(apiDomain, '/api/turnkey/external-transaction', {
        orgId: externalSubOrgId,
        transactionData: base64Transaction,
        address: address,
        type: 'addSignature',
        chainId,
      });
    },
  } as any;
};
