/**
 * Crypto Store for Hero Vault Extension
 * 
 * This store manages cryptographic operations such as:
 * - Encryption/decryption using the keyspace's symmetric cipher
 * - Signing/verification using the selected keypair
 */

import { create } from 'zustand';
import { getWasmModule, stringToUint8Array, uint8ArrayToString } from '../wasm/wasmHelper';

// Helper functions for Unicode-safe base64 encoding/decoding
function base64Encode(data: Uint8Array): string {
  // Convert binary data to a string that only uses the low 8 bits of each character
  const binaryString = Array.from(data)
    .map(byte => String.fromCharCode(byte))
    .join('');
  
  // Use btoa on the binary string
  return btoa(binaryString);
}

function base64Decode(base64: string): Uint8Array {
  // Decode base64 to binary string
  const binaryString = atob(base64);
  
  // Convert binary string to Uint8Array
  const bytes = new Uint8Array(binaryString.length);
  for (let i = 0; i < binaryString.length; i++) {
    bytes[i] = binaryString.charCodeAt(i);
  }
  
  return bytes;
}

interface CryptoState {
  // State
  isEncrypting: boolean;
  isDecrypting: boolean;
  isSigning: boolean;
  isVerifying: boolean;
  error: string | null;
  
  // Actions
  encryptData: (data: string) => Promise<string>;
  decryptData: (encrypted: string) => Promise<string>;
  signMessage: (message: string) => Promise<string>;
  verifySignature: (message: string, signature: string) => Promise<boolean>;
  clearError: () => void;
}

export const useCryptoStore = create<CryptoState>()((set, get) => ({
  isEncrypting: false,
  isDecrypting: false,
  isSigning: false,
  isVerifying: false,
  error: null,
  
  encryptData: async (data: string) => {
    try {
      set({ isEncrypting: true, error: null });
      const wasmModule = await getWasmModule();
      
      // Convert input to Uint8Array
      const dataBytes = stringToUint8Array(data);
      
      // Encrypt the data
      const encrypted = await wasmModule.encrypt_data(dataBytes);
      
      // Convert result to base64 for storage/display using our Unicode-safe function
      const encryptedBase64 = base64Encode(encrypted);
      
      return encryptedBase64;
    } catch (error) {
      set({ error: (error as Error).message || 'Failed to encrypt data' });
      throw error;
    } finally {
      set({ isEncrypting: false });
    }
  },
  
  decryptData: async (encrypted: string) => {
    try {
      set({ isDecrypting: true, error: null });
      const wasmModule = await getWasmModule();
      
      // Convert input from base64 using our Unicode-safe function
      const encryptedBytes = base64Decode(encrypted);
      
      // Decrypt the data
      const decrypted = await wasmModule.decrypt_data(encryptedBytes);
      
      // Convert result to string
      return uint8ArrayToString(decrypted);
    } catch (error) {
      set({ error: (error as Error).message || 'Failed to decrypt data' });
      throw error;
    } finally {
      set({ isDecrypting: false });
    }
  },
  
  signMessage: async (message: string) => {
    try {
      set({ isSigning: true, error: null });
      const wasmModule = await getWasmModule();
      
      // Convert message to Uint8Array
      const messageBytes = stringToUint8Array(message);
      
      // Sign the message
      const signature = await wasmModule.sign(messageBytes);
      
      return signature;
    } catch (error) {
      set({ error: (error as Error).message || 'Failed to sign message' });
      throw error;
    } finally {
      set({ isSigning: false });
    }
  },
  
  verifySignature: async (message: string, signature: string) => {
    try {
      set({ isVerifying: true, error: null });
      const wasmModule = await getWasmModule();
      
      // Convert inputs
      const messageBytes = stringToUint8Array(message);
      
      // Verify the signature
      const isValid = await wasmModule.verify(messageBytes, signature);
      
      return isValid;
    } catch (error) {
      set({ error: (error as Error).message || 'Failed to verify signature' });
      throw error;
    } finally {
      set({ isVerifying: false });
    }
  },
  
  clearError: () => set({ error: null })
}));
