// @blocklet/sdk/lib/wallet shim
// Uses @ocap/wallet to create real wallets from APP_SK for on-chain operations
import * as Mcrypto from '@ocap/mcrypto';
import { fromSecretKey } from '@ocap/wallet';

const walletTypeArcblock = {
  role: Mcrypto.types.RoleType.ROLE_APPLICATION,
  pk: Mcrypto.types.KeyType.ED25519,
  hash: Mcrypto.types.HashType.SHA3,
};

const walletTypeEthereum = {
  role: Mcrypto.types.RoleType.ROLE_APPLICATION,
  pk: Mcrypto.types.KeyType.SECP256K1,
  hash: Mcrypto.types.HashType.KECCAK,
};

// Cache wallets per type so they are not re-created on every call
let _arcblockWallet: any = null;
let _ethereumWallet: any = null;
let _lastSK: string = '';

function getAppSK(): string {
  return (globalThis as any).__CF_ENV__?.APP_SK || process.env.APP_SK || '';
}

function ensureWallet(type?: string): any {
  const sk = getAppSK();
  if (!sk) {
    return null;
  }

  // If SK changed, invalidate cached wallets
  if (sk !== _lastSK) {
    _arcblockWallet = null;
    _ethereumWallet = null;
    _lastSK = sk;
  }

  try {
    if (type === 'ethereum') {
      if (!_ethereumWallet) {
        // Ethereum wallet uses first 66 chars of SK (0x + 32 bytes hex)
        // matching @blocklet/sdk behavior: appSk.slice(0, 66)
        const ethSk = sk.slice(0, 66);
        _ethereumWallet = fromSecretKey(ethSk, walletTypeEthereum);
      }
      return _ethereumWallet;
    }

    if (!_arcblockWallet) {
      _arcblockWallet = fromSecretKey(sk, walletTypeArcblock);
    }
    return _arcblockWallet;
  } catch (e: any) {
    console.error(`[CF Worker] ensureWallet(${type}) failed:`, e?.message);
    return null;
  }
}

/**
 * Returns a wallet proxy that lazily initializes the real wallet on first property access.
 * This is needed because auth.ts calls getWallet() at module init time, before __CF_ENV__
 * is available. The proxy defers the real wallet creation to request time.
 */
export function getWallet(type?: string, _appSk?: string, _keyType?: string): any {
  return new Proxy(
    {},
    {
      get(_target, prop) {
        const realWallet = ensureWallet(type);
        if (!realWallet) {
          if (prop === 'address') return '';
          if (prop === 'publicKey') return '';
          if (prop === 'toJSON') return () => ({});
          if (prop === 'sign') return async () => '';
          if (prop === 'verify') return async () => true;
          if (prop === 'signJWT') return async () => '';
          if (prop === 'then') return undefined;
          return undefined;
        }
        const value = realWallet[prop];
        if (typeof value === 'function') {
          return value.bind(realWallet);
        }
        return value;
      },
      has(_target, prop) {
        const realWallet = ensureWallet(type);
        if (!realWallet) return false;
        return prop in realWallet;
      },
    }
  );
}

// CF shim re-exports: on CF the runtime/permanent/access wallets all derive
// from the single APP_SK, so these just alias getWallet. Needed because
// payment-kit's api/src/libs/auth.ts imports { getAccessWallet } and the
// patch in that file calls getWallet(undefined, '', 'sk').
export const getAccessWallet = () => getWallet('arcblock');
export const getPermanentWallet = () => getWallet('arcblock');
export const getEthereumWallet = () => getWallet('ethereum');
