import sys
import os
import json
import argparse
import httpx
from typing import Optional, List, Dict, Any
import glob

class VoniCLI:
    def __init__(self, api_url: Optional[str] = None):
        self.api_url = (api_url or os.getenv("VONI_API_URL", "https://api.voni.dev")).rstrip('/')
        self.config_path = os.path.expanduser("~/.voni/config.json")
        self.api_key = self._load_api_key()

    def _load_api_key(self) -> Optional[str]:
        if os.path.exists(self.config_path):
            with open(self.config_path, 'r') as f:
                config = json.load(f)
                return config.get("api_key")
        return None

    def _save_api_key(self, api_key: str):
        os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
        with open(self.config_path, 'w') as f:
            json.dump({"api_key": api_key}, f)
        os.chmod(self.config_path, 0o600)

    def _get_headers(self) -> Dict[str, str]:
        if not self.api_key:
            print("Error: Not authenticated. Run 'voni login <api_key>' first.")
            sys.exit(1)
        return {"X-API-Key": self.api_key}

    def login(self, api_key: str):
        """Authenticate the CLI with an API key."""
        try:
            response = httpx.get(
                f"{self.api_url}/api/v1/projects/",
                headers={"X-API-Key": api_key}
            )
            if response.status_code == 200:
                self._save_api_key(api_key)
                print("Successfully authenticated with Voni!")
            else:
                print(f"Error: Invalid API key (Status: {response.status_code})")
                sys.exit(1)
        except Exception as e:
            print(f"Connection error: {e}")
            sys.exit(1)

    def list_projects(self):
        """List all projects for the authenticated user."""
        try:
            response = httpx.get(
                f"{self.api_url}/api/v1/projects/",
                headers=self._get_headers()
            )
            if response.status_code == 200:
                projects = response.json()
                if not projects:
                    print("No projects found.")
                    return
                
                print("\n--- YOUR PROJECTS ---")
                print(f"{'ID':<38} {'NAME':<30} {'TYPE':<15}")
                print("-" * 83)
                for p in projects:
                    print(f"{p['id']:<38} {p['name']:<30} {p['project_type']:<15}")
            else:
                print(f"Error: Failed to list projects. {response.text}")
        except Exception as e:
            print(f"Connection error: {e}")

    def init_project(self, name: str, project_type: str = "assistant"):
        """Create a new project."""
        try:
            response = httpx.post(
                f"{self.api_url}/api/v1/projects/",
                headers=self._get_headers(),
                json={
                    "name": name,
                    "project_type": project_type
                }
            )
            if response.status_code == 201:
                project = response.json()
                print(f"\n🚀 Project '{name}' ({project_type}) created successfully!")
                print(f"Project ID: {project['id']}")
                print("\n--- INTEGRATION SNIPPET (HTML) ---")
                print(f'<script src="{self.api_url}/api/v1/widget/{project["id"]}/widget.js" async defer></script>')
                print("\n--- INTEGRATION SNIPPET (API/HEADLESS) ---")
                print(f"Endpoint: {self.api_url}/api/v1/widget/{project['id']}/chat")
                print("Usage: Send POST with { 'message': '...', 'session_id': '...' }")
                print("\nManage your project at: https://voni.dev/dashboard")
            else:
                print(f"Error: Failed to create project. {response.text}")
        except Exception as e:
            print(f"Connection error: {e}")

    def delete_project(self, project_id: str):
        """Delete a project."""
        try:
            response = httpx.delete(
                f"{self.api_url}/api/v1/projects/{project_id}",
                headers=self._get_headers()
            )
            if response.status_code == 204:
                print(f"Project {project_id} deleted successfully.")
            else:
                print(f"Error: Failed to delete project. {response.text}")
        except Exception as e:
            print(f"Connection error: {e}")

    def get_captcha(self, project_id: str):
        """Get a CAPTCHA challenge for a project."""
        try:
            response = httpx.get(
                f"{self.api_url}/api/v1/widget/{project_id}/captcha",
                headers=self._get_headers()
            )
            if response.status_code == 200:
                data = response.json()
                print("\n--- CAPTCHA CHALLENGE ---")
                print(f"Token: {data['token']}")
                print(f"Question: {data['question']}")
                return data
            else:
                print(f"Error: Failed to get captcha. {response.text}")
        except Exception as e:
            print(f"Connection error: {e}")

    def verify_captcha(self, project_id: str, token: str, answer: str):
        """Verify a CAPTCHA answer."""
        try:
            response = httpx.post(
                f"{self.api_url}/api/v1/widget/{project_id}/captcha/verify",
                headers={"Content-Type": "application/json"},
                json={"token": token, "answer": answer}
            )
            if response.status_code == 200:
                result = response.json()
                if result.get("success"):
                    print("\n✅ Verification Successful!")
                else:
                    print("\n❌ Verification Failed.")
            else:
                print(f"Error: Verification failed. {response.text}")
        except Exception as e:
            print(f"Connection error: {e}")

    def chat(self, project_id: str, message: str, session_id: Optional[str] = None):
        """Send a message to a project and display the response (including automation actions)."""
        try:
            response = httpx.post(
                f"{self.api_url}/api/v1/widget/{project_id}/chat",
                headers=self._get_headers(),
                json={
                    "message": message,
                    "session_id": session_id
                }
            )
            if response.status_code == 200:
                res_data = response.json()
                print(f"\n🤖 Voni: {res_data.get('response', res_data.get('message', ''))}")
                
                actions = res_data.get("actions", [])
                if actions:
                    print("\n⚡ AUTOMATION ACTIONS:")
                    for i, action in enumerate(actions, 1):
                        action_type = action.get('action', 'unknown')
                        selector = action.get('selector', 'N/A')
                        value = action.get('value', '')
                        print(f"  {i}. {action_type.upper()}: {selector}")
                        if value:
                            print(f"     Value: {value}")
                
                if res_data.get("session_id"):
                    print(f"\nSession ID: {res_data['session_id']}")
            else:
                print(f"Error: {response.status_code} - {response.text}")
        except Exception as e:
            print(f"Connection error: {e}")

    def sync_knowledge(self, project_id: str, directory: str):
        """Sync a directory of markdown/text files to a project's knowledge base."""
        if not os.path.isdir(directory):
            print(f"Error: {directory} is not a valid directory.")
            return

        files = []
        for ext in ('*.md', '*.txt'):
            files.extend(glob.glob(os.path.join(directory, '**', ext), recursive=True))

        if not files:
            print(f"No .md or .txt files found in {directory}")
            return

        print(f"Found {len(files)} files. Syncing to project {project_id}...")
        
        for file_path in files:
            try:
                with open(file_path, 'r') as f:
                    content = f.read()
                
                response = httpx.post(
                    f"{self.api_url}/api/v1/projects/{project_id}/knowledge/",
                    headers=self._get_headers(),
                    json={
                        "title": os.path.basename(file_path),
                        "content": content,
                        "source_type": "file",
                        "metadata": {"path": file_path}
                    }
                )
                if response.status_code in (200, 201):
                    print(f"  ✅ Synced: {os.path.basename(file_path)}")
                else:
                    print(f"  ❌ Failed: {os.path.basename(file_path)} ({response.status_code})")
            except Exception as e:
                print(f"  ❌ Error reading {file_path}: {e}")

    def learn_url(self, project_id: str, url: str):
        """Add a URL to the project's knowledge base."""
        try:
            response = httpx.post(
                f"{self.api_url}/api/v1/projects/{project_id}/knowledge/",
                headers=self._get_headers(),
                json={
                    "source_url": url,
                    "source_type": "url"
                }
            )
            if response.status_code in (200, 201):
                print(f"✅ Voni is now learning from: {url}")
            else:
                print(f"Error: Failed to learn URL. {response.text}")
        except Exception as e:
            print(f"Connection error: {e}")

    def get_project(self, project_id: str) -> Dict[str, Any]:
        """Get project details."""
        response = httpx.get(
            f"{self.api_url}/api/v1/projects/{project_id}",
            headers=self._get_headers()
        )
        if response.status_code == 200:
            return response.json()
        raise Exception(f"Failed to get project: {response.text}")

    def update_project_settings(self, project_id: str, widget_settings: Dict[str, Any]):
        """Update project widget settings."""
        response = httpx.patch(
            f"{self.api_url}/api/v1/projects/{project_id}",
            headers=self._get_headers(),
            json={"widget_settings": widget_settings}
        )
        if response.status_code == 200:
            print("✅ Settings updated successfully.")
        else:
            print(f"Error: Failed to update settings. {response.text}")

    def list_quick_actions(self, project_id: str):
        """List quick actions for a project."""
        try:
            project = self.get_project(project_id)
            settings = project.get("widget_settings", {}) or {}
            actions = settings.get("quick_actions", [])
            auto = settings.get("auto_generate_quick_actions", False)
            
            print(f"\n--- QUICK ACTIONS (Auto-generate: {auto}) ---")
            if not actions:
                print("No quick actions configured.")
            for i, action in enumerate(actions, 1):
                print(f"{i}. {action.get('label')} -> {action.get('message')}")
        except Exception as e:
            print(f"Error: {e}")

    def add_quick_action(self, project_id: str, label: str, message: str):
        """Add a quick action."""
        try:
            project = self.get_project(project_id)
            settings = project.get("widget_settings", {}) or {}
            actions = settings.get("quick_actions", []) or []
            actions.append({"label": label, "message": message})
            settings["quick_actions"] = actions
            self.update_project_settings(project_id, settings)
        except Exception as e:
            print(f"Error: {e}")

    def set_quick_actions_auto(self, project_id: str, enable: bool):
        """Set auto-generate quick actions flag."""
        try:
            project = self.get_project(project_id)
            settings = project.get("widget_settings", {}) or {}
            settings["auto_generate_quick_actions"] = enable
            self.update_project_settings(project_id, settings)
        except Exception as e:
            print(f"Error: {e}")

def main():
    parser = argparse.ArgumentParser(description="Voni AI CLI")
    subparsers = parser.add_subparsers(dest="command", help="Command to run")

    # Auth
    login_parser = subparsers.add_parser("login", help="Login with API key")
    login_parser.add_argument("api_key", help="Your Voni API Key")

    # Projects
    subparsers.add_parser("projects", help="List projects")
    
    init_parser = subparsers.add_parser("init", help="Create a new project")
    init_parser.add_argument("name", help="Project name")
    init_parser.add_argument("--type", default="assistant", help="Project type (assistant/orchestrator)")

    delete_parser = subparsers.add_parser("delete", help="Delete a project")
    delete_parser.add_argument("project_id", help="Project ID")

    # Captcha
    captcha_parser = subparsers.add_parser("captcha", help="Captcha operations")
    captcha_subparsers = captcha_parser.add_subparsers(dest="captcha_command", help="Captcha command")
    
    captcha_get = captcha_subparsers.add_parser("get", help="Get a captcha challenge")
    captcha_get.add_argument("project_id", help="Project ID")
    
    captcha_verify = captcha_subparsers.add_parser("verify", help="Verify a captcha answer")
    captcha_verify.add_argument("project_id", help="Project ID")
    captcha_verify.add_argument("token", help="Captcha token")
    captcha_verify.add_argument("answer", help="Answer to the question")

    # Chat
    chat_parser = subparsers.add_parser("chat", help="Chat with a project")
    chat_parser.add_argument("project_id", help="Project ID")
    chat_parser.add_argument("message", help="Message to send")
    chat_parser.add_argument("--session", help="Session ID")

    # Knowledge
    sync_parser = subparsers.add_parser("sync", help="Sync knowledge base from local files")
    sync_parser.add_argument("project_id", help="Project ID")
    sync_parser.add_argument("directory", help="Directory containing .md/.txt files")

    learn_parser = subparsers.add_parser("learn", help="Learn from a URL")
    learn_parser.add_argument("project_id", help="Project ID")
    learn_parser.add_argument("url", help="URL to crawl and learn")

    # Quick Actions
    qa_parser = subparsers.add_parser("quick-actions", help="Manage Quick Action settings")
    qa_subparsers = qa_parser.add_subparsers(dest="qa_command", help="Quick Action command")
    
    qa_list = qa_subparsers.add_parser("list", help="List quick actions")
    qa_list.add_argument("project_id", help="Project ID")

    qa_add = qa_subparsers.add_parser("add", help="Add a quick action")
    qa_add.add_argument("project_id", help="Project ID")
    qa_add.add_argument("label", help="Button label")
    qa_add.add_argument("message", help="Message to send")

    qa_auto = qa_subparsers.add_parser("auto", help="Set auto-generation")
    qa_auto.add_argument("project_id", help="Project ID")
    qa_auto.add_argument("state", choices=["on", "off"], help="Enable or disable auto-generation")

    args = parser.parse_args()
    cli = VoniCLI()

    if args.command == "login":
        cli.login(args.api_key)
    elif args.command == "projects":
        cli.list_projects()
    elif args.command == "init":
        cli.init_project(args.name, args.type)
    elif args.command == "delete":
        cli.delete_project(args.project_id)
    elif args.command == "captcha":
        if args.captcha_command == "get":
            cli.get_captcha(args.project_id)
        elif args.captcha_command == "verify":
            cli.verify_captcha(args.project_id, args.token, args.answer)
        else:
            captcha_parser.print_help()
    elif args.command == "quick-actions":
        if args.qa_command == "list":
            cli.list_quick_actions(args.project_id)
        elif args.qa_command == "add":
            cli.add_quick_action(args.project_id, args.label, args.message)
        elif args.qa_command == "auto":
            cli.set_quick_actions_auto(args.project_id, args.state == "on")
        else:
            qa_parser.print_help()
    elif args.command == "chat":
        cli.chat(args.project_id, args.message, args.session)
    elif args.command == "sync":
        cli.sync_knowledge(args.project_id, args.directory)
    elif args.command == "learn":
        cli.learn_url(args.project_id, args.url)
    else:
        parser.print_help()

if __name__ == "__main__":
    main()
