import subprocess
import json
import logging
from typing import List, Dict, Optional

class LastPassError(Exception):
    """Base exception for LastPass operations."""
    pass

class LastPassVault:
    """A wrapper around the LastPass CLI (lpass)."""

    def __init__(self, lpass_path: str = "lpass"):
        self.lpass_path = lpass_path

    def _run_command(self, args: List[str], input_data: Optional[str] = None) -> str:
        """Run an lpass command and return the output."""
        try:
            command = [self.lpass_path] + args
            result = subprocess.run(
                command,
                input=input_data,
                capture_output=True,
                text=True,
                check=True
            )
            return result.stdout.strip()
        except subprocess.CalledProcessError as e:
            error_msg = e.stderr.strip() or e.stdout.strip()
            raise LastPassError(f"Command '{' '.join(command)}' failed: {error_msg}")

    def login(self, username: str, password: Optional[str] = None) -> bool:
        """Log into LastPass. If password is not provided, it will be prompted by lpass."""
        try:
            args = ["login", username]
            self._run_command(args, input_data=password)
            return True
        except LastPassError as e:
            logging.error(f"Login failed: {e}")
            return False

    def logout(self, force: bool = False) -> bool:
        """Log out of LastPass."""
        try:
            args = ["logout"]
            if force:
                args.append("--force")
            self._run_command(args)
            return True
        except LastPassError:
            return False

    def is_logged_in(self) -> bool:
        """Check if currently logged into LastPass."""
        try:
            self._run_command(["status"])
            return True
        except LastPassError:
            return False

    def sync(self) -> bool:
        """Synchronize the vault with the server."""
        try:
            self._run_command(["sync"])
            return True
        except LastPassError:
            return False

    def list_items(self) -> List[Dict[str, str]]:
        """List all items in the vault."""
        try:
            output = self._run_command(["ls", "--format", "%ai|%an|%au"])
        except LastPassError:
            return []
            
        items = []
        for line in output.splitlines():
            if not line.strip():
                continue
            parts = line.split("|")
            if len(parts) == 3:
                items.append({
                    "id": parts[0].strip(),
                    "name": parts[1].strip(),
                    "username": parts[2].strip()
                })
        return items

    def get_password(self, item_name_or_id: str) -> Optional[str]:
        """Retrieve the password for a specific item."""
        try:
            return self._run_command(["show", "--password", item_name_or_id])
        except LastPassError:
            return None

    def get_item_details(self, item_name_or_id: str) -> Dict[str, str]:
        """Retrieve full details for a specific item."""
        try:
            output = self._run_command(["show", "--all", item_name_or_id])
        except LastPassError:
            return {}
            
        details = {}
        for line in output.splitlines():
            if ":" in line:
                key, value = line.split(":", 1)
                details[key.strip()] = value.strip()
        return details

    def search(self, query: str) -> List[Dict[str, str]]:
        """Search for items in the vault matching the query."""
        all_items = self.list_items()
        return [item for item in all_items if query.lower() in item["name"].lower() or query.lower() in item["username"].lower()]

if __name__ == "__main__":
    # Example usage (caution with credentials)
    # vault = LastPassVault()
    # if not vault.is_logged_in():
    #     print("Not logged in. Use vault.login(username, password)")
    # else:
    #     print("Logged in!")
    #     items = vault.list_items()
    #     print(f"Vault contains {len(items)} items.")
    pass
