import JSZip from 'jszip';
import { EncryptionMode } from './types';

// Top-level imports (Vite bundles them as strings)
import bip39WordlistRaw from '../bip39_wordlist.txt?raw';
import offlinePlaybookRaw from '../../doc/offline_recovery_playbook.md?raw';

interface RecoveryKitParams {
    encryptedData: string | Uint8Array;
    encryptionMode: EncryptionMode;
    encryptionMethod: 'password' | 'publickey' | 'both';
    fingerprint?: string;
    qrImageDataUrl?: string; // Base64 PNG from QR canvas
}

export async function generateRecoveryKit(params: RecoveryKitParams): Promise<Blob> {
    const zip = new JSZip();

    // 1. Add encrypted backup files
    zip.file('backup_encrypted.txt',
        typeof params.encryptedData === 'string'
            ? params.encryptedData
            : new Uint8Array(params.encryptedData)
    );

    if (params.qrImageDataUrl) {
        // Convert base64 data URL to binary
        const base64Data = params.qrImageDataUrl.split(',')[1];
        zip.file('backup_qr.png', base64Data, { base64: true });
    }

    // 2. Add recovery scripts (get from embedded templates)
    const scripts = getRecoveryScripts(params.encryptionMode);
    Object.entries(scripts).forEach(([filename, content]) => {
        zip.file(filename, content);
    });

    // 3. Add personalized instructions
    const instructions = getPersonalizedInstructions(params);
    zip.file('RECOVERY_INSTRUCTIONS.md', instructions);

    // 4. Add BIP39 wordlist (fetch from public source or embed)
    const wordlist = await fetchBIP39Wordlist();
    zip.file('bip39_wordlist.txt', wordlist);

    // 5. Add offline recovery playbook
    zip.file('OFFLINE_RECOVERY_PLAYBOOK.md', offlinePlaybookRaw);

    // 6. Add metadata
    const metadata = {
        format: params.encryptionMode,
        encryption_method: params.encryptionMethod,
        created: new Date().toISOString(),
        fingerprint: params.fingerprint || null,
        recovery_playbook_url: 'https://github.com/kccleoc/seedpgp-web/blob/main/doc/OFFLINE_RECOVERY_PLAYBOOK.md',
        offline_playbook_included: true,
    };
    zip.file('recovery_info.json', JSON.stringify(metadata, null, 2));

    // Generate ZIP blob
    return await zip.generateAsync({ type: 'blob' });
}

function getRecoveryScripts(mode: EncryptionMode): Record<string, string> {
    const scripts: Record<string, string> = {};

    if (mode === 'pgp') {
        scripts['decrypt_pgp.sh'] = DECRYPT_PGP_SCRIPT;
        scripts['decode_base45.py'] = DECODE_BASE45_SCRIPT;
    } else if (mode === 'krux') {
        scripts['decrypt_krux.py'] = DECRYPT_KRUX_SCRIPT;
    } else if (mode === 'seedqr') {
        scripts['decode_seedqr.py'] = DECODE_SEEDQR_SCRIPT;
    }

    return scripts;
}

function getPersonalizedInstructions(params: RecoveryKitParams): string {
    return `# Recovery Instructions for Your SeedPGP Backup

## Your Backup Details

- Format: ${params.encryptionMode.toUpperCase()}
- Encryption: ${params.encryptionMethod}
- Created: ${new Date().toLocaleDateString()}
${params.fingerprint ? `- PGP Fingerprint: ${params.fingerprint}` : ''}

## Quick Recovery Steps

${params.encryptionMode === 'pgp' ? `
### Method: GPG Command-Line

1. Extract backup_encrypted.txt from this ZIP
2. Install GPG on any computer: https://gnupg.org/download/
3. Run decryption command:

\`\`\`bash
gpg --decrypt backup_encrypted.txt
\`\`\`

4. Enter your ${params.encryptionMethod === 'password' ? 'password' : 'PGP private key passphrase'}
5. Output will be JSON format: {"v":1,"t":"bip39","w":"word1 word2..."}
6. Extract the "w" field — that's your seed phrase
` : ''}

${params.encryptionMode === 'krux' ? `
### Method: Python Script

1. Install Python 3: https://python.org/downloads/
2. Install dependencies:

\`\`\`bash
pip3 install cryptography mnemonic
\`\`\`

3. Run the decryption script:

\`\`\`bash
python3 decrypt_krux.py
\`\`\`

4. Paste your backup data when prompted
5. Enter your passphrase
6. Your seed phrase will be displayed
` : ''}

${params.encryptionMode === 'seedqr' ? `
### Method: Python Script

1. Install Python 3: https://python.org/downloads/
2. Install dependencies:

\`\`\`bash
pip3 install base45
\`\`\`

3. Run the decoding script:

\`\`\`bash
python3 decode_seedqr.py
\`\`\`

4. Paste your backup data when prompted
5. Your seed phrase will be displayed
` : ''}

## Full Documentation

See OFFLINE_RECOVERY_PLAYBOOK.md (included in this ZIP) for complete offline recovery instructions.

## Security Reminder

⚠️ Decrypt only on an air-gapped computer (TailsOS or Ubuntu Live USB)
⚠️ Never screenshot or save the decrypted seed to disk
⚠️ Write your seed on paper immediately after recovery
`;
}

async function fetchBIP39Wordlist(): Promise<string> {
    try {
        // Try network fetch first (offline recovery users can use local)
        const response = await fetch('/src/bip39_wordlist.txt');
        if (!response.ok) throw new Error('Network fetch failed');
        return await response.text();
    } catch {
        // Fallback: bundled file (works offline/air-gapped)
        return bip39WordlistRaw;
    }
}

// Embedded recovery scripts
const DECRYPT_PGP_SCRIPT = `#!/bin/bash
# Decrypt PGP-encrypted SeedPGP backup
# Usage: ./decrypt_pgp.sh <encrypted_file.txt>

if [ $# -eq 0 ]; then
    echo "Usage: $0 <encrypted_file.txt>"
    exit 1
fi

echo "Decrypting PGP backup..."
gpg --decrypt "$1" 2>/dev/null | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin)
    if data.get('t') == 'bip39':
        print('\\n✅ Seed phrase recovered:')
        print('\\n' + data['w'])
    else:
        print('\\n❌ Unexpected format:', data.get('t'))
except Exception as e:
    print('\\n❌ Failed to parse JSON:', e)
"
`;

const DECODE_BASE45_SCRIPT = `#!/usr/bin/env python3
# Decode Base45-encoded SeedPGP backup
# Usage: python3 decode_base45.py <base45_string>

import base45
import sys

def decode_base45(data: str) -> bytes:
    """Decode Base45 string to bytes."""
    return base45.b45decode(data)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python3 decode_base45.py <base45_string>")
        sys.exit(1)
    
    try:
        decoded = decode_base45(sys.argv[1])
        print(f"Decoded {len(decoded)} bytes")
        print(decoded.hex())
    except Exception as e:
        print(f"Error: {e}")
`;

const DECRYPT_KRUX_SCRIPT = `#!/usr/bin/env python3
# Decrypt Krux KEF-encrypted backup
# Usage: python3 decrypt_krux.py

import hashlib
import hmac
import json
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2
from cryptography.hazmat.backends import default_backend
from mnemonic import Mnemonic

def decrypt_krux_kef(encrypted_data: str, password: str) -> str:
    """Decrypt Krux KEF format."""
    # Implementation from seedpgp krux.ts
    import base64
    import struct
    
    data = base64.b64decode(encrypted_data)
    salt = data[:16]
    iv = data[16:32]
    ciphertext = data[32:-32]
    mac = data[-32:]
    
    # Derive key
    kdf = PBKDF2(
        algorithm=hashlib.sha256(),
        length=64,
        salt=salt,
        iterations=100000,
        backend=default_backend()
    )
    key = kdf.derive(password.encode())
    encryption_key = key[:32]
    mac_key = key[32:]
    
    # Verify MAC
    h = hmac.new(mac_key, data[:-32], hashlib.sha256)
    if not hmac.compare_digest(h.digest(), mac):
        raise ValueError("Invalid password or corrupted data")
    
    # Decrypt
    cipher = Cipher(
        algorithms.AES(encryption_key),
        modes.CTR(iv),
        backend=default_backend()
    )
    decryptor = cipher.decryptor()
    plaintext = decryptor.update(ciphertext) + decryptor.finalize()
    
    # Parse JSON
    result = json.loads(plaintext.decode())
    return result.get('w', '')

if __name__ == "__main__":
    print("Paste your encrypted Krux backup (Base64):")
    encrypted = input().strip()
    
    print("Enter your passphrase:")
    password = input().strip()
    
    try:
        seed = decrypt_krux_kef(encrypted, password)
        print(f"\\n✅ Seed phrase recovered:\\n\\n{seed}")
    except Exception as e:
        print(f"\\n❌ Decryption failed: {e}")
`;

const DECODE_SEEDQR_SCRIPT = `#!/usr/bin/env python3
# Decode SeedQR backup
# Usage: python3 decode_seedqr.py <seedqr_data>

import sys
import json

def decode_seedqr(data: str) -> str:
    """Decode SeedQR format."""
    # Check if it's numeric format
    if data.isdigit():
        # Convert numeric to hex
        hex_str = hex(int(data))[2:]
        # Pad to proper length
        if len(hex_str) % 2 != 0:
            hex_str = '0' + hex_str
        # Convert hex to bytes
        bytes_data = bytes.fromhex(hex_str)
    else:
        # Assume it's already hex
        bytes_data = bytes.fromhex(data)
    
    # Parse as JSON
    result = json.loads(bytes_data.decode())
    return result.get('w', '')

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python3 decode_seedqr.py <seedqr_data>")
        sys.exit(1)
    
    try:
        seed = decode_seedqr(sys.argv[1])
        print(f"\\n✅ Seed phrase recovered:\\n\\n{seed}")
    except Exception as e:
        print(f"\\n❌ Decoding failed: {e}")
`;

