import { getSecret } from './aes.js';
import { ApiKeyStamper, TurnkeyServerClient } from '@turnkey/sdk-server';
import { getPublicKey } from '@turnkey/crypto';
import { createAccount } from '@turnkey/viem';
import { createWalletClient, fallback, http, WalletClient, Chain } from 'viem';
import { getRpcUrls, getEthChainViem, SOLANA_CHAIN_ID } from '@shogun-sdk/money-legos';
import { TurnkeySigner } from '@turnkey/solana';

export function uint8ArrayToHex(uint8Array: Uint8Array): string {
  return Array.from(uint8Array)
    .map((byte) => byte.toString(16).padStart(2, '0'))
    .join('');
}

export const getTurnkeyClient = async (
  orgId: string,
  encryptedPrivateKey: string,
  publicOrganizationId: string,
  dataEncryptionKey: string,
): Promise<TurnkeyServerClient> => {
  if (!orgId) {
    throw new Error('Org ID is required');
  }

  const decryptedPrivateKey = getSecret(orgId, encryptedPrivateKey, publicOrganizationId, dataEncryptionKey);

  if (!decryptedPrivateKey) {
    throw new Error('Failed to decrypt private key');
  }

  const publicKey = uint8ArrayToHex(getPublicKey(decryptedPrivateKey));
  const user_stamper = new ApiKeyStamper({
    apiPublicKey: publicKey,
    apiPrivateKey: decryptedPrivateKey,
  });

  return new TurnkeyServerClient({
    apiBaseUrl: 'https://api.turnkey.com',
    organizationId: orgId,
    stamper: user_stamper,
  });
};

/**
 * Returns a Viem WalletClient for EVM chains using Turnkey Server.
 * @param orgId Organization ID
 * @param walletAddress The EVM address to sign with
 * @param chainId The EVM chain ID
 */
export const getEVMSignerTurnkeyServer = async (
  orgId: string,
  walletAddress: string,
  chainId: number,
  encryptedPrivateKey: string,
  publicOrganizationId: string,
  dataEncryptionKey: string,
): Promise<WalletClient> => {
  if (!orgId) {
    throw new Error('Org ID is required');
  }

  if (!walletAddress) {
    throw new Error('Wallet address is required');
  }

  const decryptedPrivateKey = getSecret(orgId, encryptedPrivateKey, publicOrganizationId, dataEncryptionKey);

  if (!decryptedPrivateKey) {
    throw new Error('Failed to decrypt private key');
  }

  const publicKey = uint8ArrayToHex(getPublicKey(decryptedPrivateKey));
  const user_stamper = new ApiKeyStamper({
    apiPublicKey: publicKey,
    apiPrivateKey: decryptedPrivateKey,
  });

  const httpClient = new TurnkeyServerClient({
    apiBaseUrl: 'https://api.turnkey.com',
    organizationId: orgId,
    stamper: user_stamper,
  });

  // Use the same logic as getEVMChains to get the correct chain object
  const chain = getEthChainViem(chainId) as Chain;
  if (!chain) {
    throw new Error(`Unsupported EVM chainId: ${chainId}`);
  }

  const turnkeyAccount = await createAccount({
    client: httpClient as any,
    organizationId: orgId,
    signWith: walletAddress,
    ethereumAddress: walletAddress,
  });

  const rpcUrls = getRpcUrls()[chainId]?.rpc;

  if (!rpcUrls || rpcUrls.length === 0) {
    throw new Error(`No RPC URLs found for chainId: ${chainId}`);
  }

  const transports = rpcUrls.map((url: string) => http(url));
  const client = createWalletClient({
    account: turnkeyAccount as any,
    chain,
    transport: fallback(transports),
  });

  return client;
};

/**
 * Returns a TurnkeySigner for Solana using Turnkey Server.
 * @param orgId Organization ID
 * @param address The Solana address to sign with (optional, not required for TurnkeySigner)
 */
export const getTurnkeySolanaSignerServer = async (
  orgId: string,
  encryptedPrivateKey: string,
  publicOrganizationId: string,
  dataEncryptionKey: string,
): Promise<TurnkeySigner> => {
  if (!orgId) {
    throw new Error('Org ID is required');
  }

  const decryptedPrivateKey = getSecret(orgId, encryptedPrivateKey, publicOrganizationId, dataEncryptionKey);

  if (!decryptedPrivateKey) {
    throw new Error('Failed to decrypt private key');
  }

  const publicKey = uint8ArrayToHex(getPublicKey(decryptedPrivateKey));
  const user_stamper = new ApiKeyStamper({
    apiPublicKey: publicKey,
    apiPrivateKey: decryptedPrivateKey,
  });

  const httpClient = new TurnkeyServerClient({
    apiBaseUrl: 'https://api.turnkey.com',
    organizationId: orgId,
    stamper: user_stamper,
  });

  const turnkeySigner = new TurnkeySigner({
    organizationId: orgId,
    client: httpClient as any,
  });

  return turnkeySigner;
};

export const getChainTurnkeySigner = (
  chainId: number,
): typeof getEVMSignerTurnkeyServer | typeof getTurnkeySolanaSignerServer => {
  if (chainId === SOLANA_CHAIN_ID) {
    return getTurnkeySolanaSignerServer;
  }
  return getEVMSignerTurnkeyServer;
};
