"""
Password Manager CLI
A simple command-line password storage system with basic encryption.

Covers: Dictionaries, functions, loops, error handling, file I/O, input validation
Security Note: This uses basic XOR encryption for learning purposes only.
Real password managers use much stronger encryption (AES-256, etc.)
"""

import json
import os
import getpass
from datetime import datetime


# File where passwords are stored
VAULT_FILE = "password_vault.json"


def simple_encrypt(text, key):
    """
    Simple XOR encryption for learning purposes.
    In production, use proper encryption libraries like cryptography.
    
    Args:
        text: String to encrypt
        key: Encryption key (string)
    
    Returns:
        Encrypted string in hexadecimal format
    """
    # Convert key to bytes and repeat to match text length
    key_bytes = (key * (len(text) // len(key) + 1))[:len(text)].encode()
    text_bytes = text.encode()
    
    # XOR each byte
    encrypted = bytes(t ^ k for t, k in zip(text_bytes, key_bytes))
    
    # Return as hexadecimal string
    return encrypted.hex()


def simple_decrypt(encrypted_hex, key):
    """
    Decrypt XOR-encrypted text.
    
    Args:
        encrypted_hex: Encrypted text in hexadecimal format
        key: Decryption key (string)
    
    Returns:
        Decrypted string
    """
    try:
        # Convert hex string back to bytes
        encrypted_bytes = bytes.fromhex(encrypted_hex)
        
        # Convert key to bytes and repeat to match encrypted length
        key_bytes = (key * (len(encrypted_bytes) // len(key) + 1))[:len(encrypted_bytes)].encode()
        
        # XOR each byte
        decrypted = bytes(e ^ k for e, k in zip(encrypted_bytes, key_bytes))
        
        return decrypted.decode()
    except Exception as e:
        raise ValueError(f"Decryption failed: {e}")


def load_vault(master_password):
    """
    Load the password vault from file.
    
    Args:
        master_password: Master password for decryption
    
    Returns:
        Dictionary containing all stored accounts
    """
    if not os.path.exists(VAULT_FILE):
        return {}
    
    try:
        # Read encrypted hex string
        with open(VAULT_FILE, 'r') as f:
            encrypted = f.read()
        
        # Decrypt to get JSON string
        decrypted_json = simple_decrypt(encrypted, master_password)
        
        # Parse JSON - THIS WILL FAIL if password was wrong!
        vault = json.loads(decrypted_json)  # ← Garbage fails here
        
        return vault
    
    except json.JSONDecodeError:
        print("⚠️  Wrong master password!")
        return None
    except Exception as e:
        print(f"⚠️  Error: {e}")
        return None


def save_vault(vault, master_password):
    """
    Save the password vault to file with encryption.
    
    Args:
        vault: Dictionary containing all accounts
        master_password: Master password for encryption
    """
    try:
        # Convert vault to JSON string
        vault_json = json.dumps(vault)
        
        # Encrypt the ENTIRE JSON string
        encrypted = simple_encrypt(vault_json, master_password)
        
        # Save encrypted string to file
        with open(VAULT_FILE, 'w') as f:
            f.write(encrypted)  # Just the hex string
        
        return True
    except Exception as e:
        print(f"✗ Error: {e}")
        return False


def add_account(vault, master_password):
    """Add a new account to the vault."""
    print("\n" + "=" * 50)
    print("ADD NEW ACCOUNT")
    print("=" * 50)
    
    # Get account name (cannot be empty)
    while True:
        account_name = input("\nAccount name (e.g., 'Gmail', 'Facebook'): ").strip()
        if account_name:
            break
        print("⚠️  Account name cannot be empty!")
    
    # Check if account already exists
    if account_name in vault:
        overwrite = input(f"⚠️  '{account_name}' already exists. Overwrite? (yes/no): ").lower()
        if overwrite != 'yes':
            print("✗ Cancelled.")
            return
    
    # Get username
    username = input("Username/Email: ").strip()
    
    # Get password (hidden input)
    while True:
        password = getpass.getpass("Password: ")
        if password:
            password_confirm = getpass.getpass("Confirm password: ")
            if password == password_confirm:
                break
            else:
                print("⚠️  Passwords don't match! Try again.")
        else:
            print("⚠️  Password cannot be empty!")
    
    # Optional fields
    url = input("Website URL (optional): ").strip()
    notes = input("Notes (optional): ").strip()
    
    # Store account
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    vault[account_name] = {
        'username': username,
        'password': password,
        'url': url,
        'notes': notes,
        'created': now,
        'modified': now
    }
    
    save_vault(vault, master_password)
    print(f"\n✓ Account '{account_name}' added successfully!")


def view_account(vault):        # TODO phase 3
    """View details of a specific account."""
    if not vault:
        print("\n⚠️  Vault is empty! Add an account first.")
        return
    
    print("\n" + "=" * 50)
    print("VIEW ACCOUNT")
    print("=" * 50)
    
    # Show available accounts
    print("\nStored accounts:")
    for i, account in enumerate(vault.keys(), 1):
        print(f"  {i}. {account}")
    
    account_name = input("\nEnter account name: ").strip()
    
    if account_name not in vault:
        print(f"✗ Account '{account_name}' not found!")
        return
    
    # Display account details
    account = vault[account_name]
    print("\n" + "-" * 50)
    print(f"Account: {account_name}")
    print("-" * 50)
    print(f"Username:  {account['username']}")
    print(f"Password:  {account['password']}")
    if account.get('url'):
        print(f"URL:       {account['url']}")
    if account.get('notes'):
        print(f"Notes:     {account['notes']}")
    print(f"Created:   {account.get('created', 'Unknown')}")
    print(f"Modified:  {account.get('modified', 'Unknown')}")
    print("-" * 50)


def list_accounts(vault):       # TODO pahse 3
    """List all stored accounts."""
    if not vault:
        print("\n⚠️  Vault is empty! No accounts stored.")
        return
    
    print("\n" + "=" * 50)
    print(f"STORED ACCOUNTS ({len(vault)} total)")
    print("=" * 50)
    
    for account_name, data in vault.items():
        print(f"\n📧 {account_name}")
        print(f"   Username: {data['username']}")
        if data.get('url'):
            print(f"   URL: {data['url']}")


def delete_account(vault, master_password):
    """Delete an account from the vault."""
    if not vault:
        print("\n⚠️  Vault is empty! Nothing to delete.")
        return
    
    print("\n" + "=" * 50)
    print("DELETE ACCOUNT")
    print("=" * 50)
    
    # Show available accounts
    print("\nStored accounts:")
    for i, account in enumerate(vault.keys(), 1):
        print(f"  {i}. {account}")
    
    account_name = input("\nEnter account name to delete: ").strip()
    
    if account_name not in vault:
        print(f"✗ Account '{account_name}' not found!")
        return
    
    # Confirm deletion
    confirm = input(f"⚠️  Are you sure you want to delete '{account_name}'? (yes/no): ").lower()
    if confirm == 'yes':
        del vault[account_name]
        save_vault(vault, master_password)
        print(f"✓ Account '{account_name}' deleted successfully!")
    else:
        print("✗ Cancelled.")


def search_accounts(vault):
    """Search for accounts by name."""
    if not vault:
        print("\n⚠️  Vault is empty! Nothing to search.")
        return
    
    query = input("\nSearch for account: ").strip().lower()
    
    results = [account for account in vault.keys() if query in account.lower()]
    
    if results:
        print(f"\n✓ Found {len(results)} result(s):")
        for account in results:
            print(f"  • {account}")
    else:
        print(f"✗ No accounts found matching '{query}'")


def show_help():
    """Display available commands."""
    print("\n" + "=" * 50)
    print("AVAILABLE COMMANDS")
    print("=" * 50)
    print("  add      - Add a new account")
    print("  view     - View account details")
    print("  list     - List all accounts")
    print("  search   - Search for accounts")
    print("  delete   - Delete an account")
    print("  help     - Show this help")
    print("  quit     - Exit password manager")
    print("=" * 50)


def main():
    """Main program loop."""
    print("\n" + "=" * 50)
    print("🔐  PASSWORD MANAGER CLI  🔐")
    print("=" * 50)
    print("\n⚠️  SECURITY NOTE: This is for learning purposes only!")
    print("Use a real password manager (1Password, Bitwarden, etc.)")
    print("for actual sensitive data.\n")
    
    # Get master password
    master_password = getpass.getpass("Enter master password: ")
    
    if not master_password:
        print("✗ Master password cannot be empty!")
        return
    
    # Load vault
    print("\n📂 Loading vault...")
    vault = load_vault(master_password)
    
    if vault is None:
        print("✗ Failed to unlock vault. Exiting.")
        return
    
    if not vault:
        print("✓ New vault created!")
    else:
        print(f"✓ Vault unlocked! ({len(vault)} accounts loaded)")
    
    show_help()
    
    # Main command loop
    while True:
        try:
            command = input("\n🔐 > ").strip().lower()
            
            if not command:
                continue
            
            if command == "quit" or command == "exit":
                print("\n👋 Locking vault and exiting. Stay secure!")
                break
            
            elif command == "help":
                show_help()
            
            elif command == "add":
                add_account(vault, master_password)
            
            elif command == "view":
                view_account(vault)
            
            elif command == "list":
                list_accounts(vault)
            
            elif command == "search":
                search_accounts(vault)
            
            elif command == "delete":
                delete_account(vault, master_password)
            
            else:
                print(f"✗ Unknown command: '{command}'. Type 'help' for available commands.")
        
        except KeyboardInterrupt:
            print("\n\n👋 Interrupted. Locking vault and exiting.")
            break
        
        except Exception as e:
            print(f"⚠️  Error: {e}")


if __name__ == "__main__":
    main()