import * as web3 from '@solana/web3.js';
import { Wallet } from './Wallet';
import bs58 from 'bs58';
import { derivePath } from 'ed25519-hd-key';

export interface SolanaKeypair {
  publicKey: web3.PublicKey;
  secretKey: Uint8Array;
}

export class SPLWallet extends Wallet {
  constructor(wallet: SolanaKeypair) {
    super(wallet);
  }

  get address(): string {
    return this.signer.publicKey.toString();
  }

  getPrivateKey(): string {
    const secretKey = this.signer.secretKey;
    const encoded = bs58.encode(secretKey);
    return encoded;
  }

  getSecretKey(): Uint8Array {
    return this.signer.secretKey;
  }

  static validate(privateKey: string): boolean {
    try {
      const toBase58 = bs58.decode(privateKey);
      const keypair = web3.Keypair.fromSecretKey(toBase58);
      if (keypair instanceof web3.Keypair) {
        return true;
      }
      return false;
    } catch (error) {
      return false;
    }
  }

  static generateWallet(): Wallet {
    const keypair = web3.Keypair.generate();
    return new SPLWallet({
      publicKey: keypair.publicKey,
      secretKey: keypair.secretKey,
    });
  }

  /**@internal*/
  static fromSeed(seed: Uint8Array): Wallet {
    const keypair = web3.Keypair.fromSeed(seed);
    return new SPLWallet({
      publicKey: keypair.publicKey,
      secretKey: keypair.secretKey,
    });
  }

  static async fromMnemonic(
    mnemonic: string,
    delivePath = "m/44'/501'/0'/0'"
  ): Promise<Wallet> {
    const seed = await this.mnemonicToSeed(mnemonic); // type Buffer
    const delivedSeed = derivePath(delivePath, seed.toString('hex')).key;

    return this.fromSeed(delivedSeed as Uint8Array);
  }

  static async generateWalletWithIndex(
    seed: Buffer,
    index: number
  ): Promise<Wallet> {
    const delivePath = `m/44'/501'/${index}'/0'`;
    // 512-bit seed
    const delivedSeed = derivePath(delivePath, seed.toString('hex')).key;
    // @TODO
    return this.fromSeed(delivedSeed as Uint8Array);
  }

  static fromSecretKey(secretKey: Uint8Array): Wallet {
    const keypair = web3.Keypair.fromSecretKey(secretKey);

    return new SPLWallet({
      publicKey: keypair.publicKey,
      secretKey: keypair.secretKey,
    });
  }

  static fromPrivateKey(secretKey: string): Wallet {
    const toBase58 = bs58.decode(secretKey);
    const keypair = web3.Keypair.fromSecretKey(toBase58);

    return new SPLWallet({
      publicKey: keypair.publicKey,
      secretKey: keypair.secretKey,
    });
  }
}
