#!/usr/bin/env python3
"""
HTTP API Examples for Local Deep Research v1.0+

This script demonstrates comprehensive usage of the LDR HTTP API with authentication.
Includes examples for research, settings management, and batch operations.

Requirements:
- LDR v1.0+ (with authentication features)
- LDR server running: python -m local_deep_research.web.app
- Beautiful Soup: pip install beautifulsoup4

================================================================================
IMPORTANT - LOCALHOST ONLY
================================================================================
This example ONLY works when connecting via localhost:
  ✅ http://localhost:5000
  ✅ http://127.0.0.1:5000

It will NOT work when connecting via:
  ❌ http://192.168.x.x:5000  (local network IP)
  ❌ http://your-server.com:5000  (remote server)

WHY: For security, session cookies require HTTPS for non-localhost connections.

SOLUTIONS for non-localhost access:
1. Use HTTPS with a reverse proxy (recommended for production)
2. SSH tunnel: ssh -L 5000:localhost:5000 user@server, then use localhost:5000
3. Set TESTING=1 when starting server (INSECURE - development only!)

WARNING: TESTING=1 disables secure cookie protection. Never use in production.
================================================================================
"""

import time
from typing import Any, Dict, List
import requests
from pathlib import Path
import sys
from bs4 import BeautifulSoup

# Add the src directory to Python path for programmatic user creation
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent / "src"))

from local_deep_research.database.encrypted_db import DatabaseManager
from local_deep_research.database.models import User
from local_deep_research.database.auth_db import auth_db_session

# Configuration
BASE_URL = "http://localhost:5000"


def create_test_user():
    """Create a test user programmatically - works out of the box!"""
    username = f"testuser_{int(time.time())}"
    password = "testpassword123"

    print(f"Creating test user: {username}")

    try:
        # Create user in auth database
        with auth_db_session() as session:
            new_user = User(username=username)
            session.add(new_user)
            session.commit()

        # Create encrypted database for user
        db_manager = DatabaseManager()
        db_manager.create_user_database(username, password)

        print(f"✅ User created successfully: {username}")
        return username, password

    except Exception as e:
        print(f"❌ Failed to create user: {e}")
        return None, None


class LDRClient:
    """Client for interacting with LDR API v1.0+ with authentication"""

    def __init__(self, base_url: str = BASE_URL):
        self.base_url = base_url
        self.session = requests.Session()
        self.csrf_token = None
        self.username = None

    def login(self, username: str, password: str) -> bool:
        """Authenticate with the LDR server."""
        try:
            # Get login page and CSRF token
            login_page = self.session.get(f"{self.base_url}/auth/login")
            if login_page.status_code != 200:
                return False

            soup = BeautifulSoup(login_page.text, "html.parser")
            csrf_input = soup.find("input", {"name": "csrf_token"})
            login_csrf = csrf_input.get("value")

            if not login_csrf:
                return False

            # Submit login form
            login_response = self.session.post(
                f"{self.base_url}/auth/login",
                data={
                    "username": username,
                    "password": password,
                    "csrf_token": login_csrf,
                },
                allow_redirects=False,
            )

            if login_response.status_code not in [200, 302]:
                return False

            self.username = username

            # Get API CSRF token for API calls
            csrf_response = self.session.get(f"{self.base_url}/auth/csrf-token")
            if csrf_response.status_code == 200:
                self.csrf_token = csrf_response.json().get("csrf_token")

            return True

        except Exception:
            return False

    def logout(self) -> None:
        """Logout from the server."""
        if self.csrf_token:
            self.session.post(
                f"{self.base_url}/auth/logout",
                headers={"X-CSRF-Token": self.csrf_token},
            )

    def _get_headers(self) -> Dict[str, str]:
        """Get headers with CSRF token."""
        return {"X-CSRF-Token": self.csrf_token} if self.csrf_token else {}

    def check_health(self) -> Dict[str, Any]:
        """Check API health status."""
        response = self.session.get(f"{self.base_url}/auth/check")
        return response.json()

    def start_research(self, query: str, **kwargs) -> Dict[str, Any]:
        """Start a new research task."""
        payload = {
            "query": query,
            "model": kwargs.get("model"),
            "search_engines": kwargs.get("search_engines", ["wikipedia"]),
            "iterations": kwargs.get("iterations", 2),
            "questions_per_iteration": kwargs.get("questions_per_iteration", 3),
            "temperature": kwargs.get("temperature", 0.7),
            "local_context": kwargs.get("local_context", 2000),
            "web_context": kwargs.get("web_context", 2000),
        }

        response = self.session.post(
            f"{self.base_url}/api/start_research",
            json=payload,
            headers=self._get_headers(),
        )

        if response.status_code == 200:
            return response.json()
        raise Exception(f"Failed to start research: {response.text}")

    def get_research_status(self, research_id: str) -> Dict[str, Any]:
        """Get the status of a research task."""
        response = self.session.get(
            f"{self.base_url}/api/research/{research_id}/status"
        )
        return response.json()

    def get_research_result(self, research_id: str) -> Dict[str, Any]:
        """Get the results of a completed research task."""
        response = self.session.get(f"{self.base_url}/api/report/{research_id}")
        return response.json()

    def wait_for_research(
        self, research_id: str, timeout: int = 300
    ) -> Dict[str, Any]:
        """Wait for research to complete and return results."""
        start_time = time.time()

        while time.time() - start_time < timeout:
            status = self.get_research_status(research_id)

            if status.get("status") == "completed":
                return self.get_research_result(research_id)
            if status.get("status") == "failed":
                raise Exception(
                    f"Research failed: {status.get('error', 'Unknown error')}"
                )

            print(
                f"  Status: {status.get('status', 'unknown')} - {status.get('progress', 'N/A')}"
            )
            time.sleep(3)

        raise TimeoutError(
            f"Research {research_id} timed out after {timeout} seconds"
        )

    def get_settings(self) -> Dict[str, Any]:
        """Get all user settings."""
        response = self.session.get(f"{self.base_url}/settings/api")
        return response.json()

    def get_setting(self, key: str) -> Any:
        """Get a specific setting value."""
        response = self.session.get(f"{self.base_url}/settings/api/{key}")
        if response.status_code == 200:
            return response.json()
        return None

    def update_setting(self, key: str, value: Any) -> bool:
        """Update a setting value."""
        response = self.session.put(
            f"{self.base_url}/settings/api/{key}",
            json={"value": value},
            headers=self._get_headers(),
        )
        return response.status_code in [200, 201]

    def get_history(self, limit: int = 10) -> List[Dict[str, Any]]:
        """Get research history."""
        response = self.session.get(
            f"{self.base_url}/history/api", params={"limit": limit}
        )
        data = response.json()
        return data.get("items", data.get("history", []))

    def get_available_models(self) -> Dict[str, str]:
        """Get available LLM providers and models."""
        response = self.session.get(
            f"{self.base_url}/settings/api/available-models"
        )
        data = response.json()
        return data.get("providers", data.get("models", {}))

    def get_available_search_engines(self) -> List[str]:
        """Get available search engines."""
        response = self.session.get(
            f"{self.base_url}/settings/api/available-search-engines"
        )
        data = response.json()
        return data.get("engines", data.get("engine_options", []))


def example_quick_research(client: LDRClient) -> None:
    """Example: Quick research with minimal parameters."""
    print("\n=== Example 1: Quick Research ===")

    research = client.start_research(
        query="What are the key principles of machine learning?",
        iterations=1,
        questions_per_iteration=2,
    )

    print(f"Started research ID: {research['research_id']}")

    # Wait for completion
    result = client.wait_for_research(research["research_id"])

    print(f"\nSummary: {result['summary'][:500]}...")
    print(f"Sources: {len(result.get('sources', []))}")
    print(f"Findings: {len(result.get('findings', []))}")


def example_detailed_research(client: LDRClient) -> None:
    """Example: Detailed research with multiple search engines."""
    print("\n=== Example 2: Detailed Research ===")

    # Check available search engines
    engines = client.get_available_search_engines()
    print(f"Available search engines: {engines}")

    # Use multiple engines
    selected_engines = (
        ["wikipedia", "arxiv"] if "arxiv" in engines else ["wikipedia"]
    )

    research = client.start_research(
        query="Impact of climate change on global food security",
        search_engines=selected_engines,
        iterations=3,
        questions_per_iteration=4,
        temperature=0.7,
    )

    print(f"Started detailed research ID: {research['research_id']}")

    # Monitor progress
    result = client.wait_for_research(research["research_id"], timeout=600)

    print(f"\nTitle: {result.get('query', 'N/A')}")
    print(f"Summary length: {len(result['summary'])} characters")
    print(f"Sources: {len(result.get('sources', []))}")

    # Show some findings
    findings = result.get("findings", [])
    if findings:
        print("\nTop findings:")
        for i, finding in enumerate(findings[:3], 1):
            print(f"{i}. {finding.get('text', 'N/A')[:100]}...")


def example_settings_management(client: LDRClient) -> None:
    """Example: Managing user settings."""
    print("\n=== Example 3: Settings Management ===")

    # Get current settings
    settings = client.get_settings()
    settings_data = settings.get("settings", {})

    # Display current LLM configuration
    llm_provider = settings_data.get("llm.provider", {}).get("value", "Not set")
    llm_model = settings_data.get("llm.model", {}).get("value", "Not set")

    print(f"Current LLM Provider: {llm_provider}")
    print(f"Current LLM Model: {llm_model}")

    # Get available models
    models = client.get_available_models()
    print(f"\nAvailable providers: {list(models.keys())}")

    # Example: Update temperature setting
    current_temp = settings_data.get("llm.temperature", {}).get("value", 0.7)
    print(f"\nCurrent temperature: {current_temp}")

    # Update temperature (example - uncomment to actually update)
    # success = client.update_setting("llm.temperature", 0.5)
    # print(f"Temperature update: {'Success' if success else 'Failed'}")


def example_batch_research(client: LDRClient) -> None:
    """Example: Running multiple research tasks in batch."""
    print("\n=== Example 4: Batch Research ===")

    queries = [
        "What is quantum entanglement?",
        "How does CRISPR gene editing work?",
        "What are the applications of blockchain technology?",
    ]

    research_ids = []

    # Start all research tasks
    for query in queries:
        try:
            research = client.start_research(
                query=query, iterations=1, questions_per_iteration=2
            )
            research_ids.append(
                {
                    "id": research["research_id"],
                    "query": query,
                    "status": "started",
                }
            )
            print(f"Started: {query} (ID: {research['research_id']})")
        except Exception as e:
            print(f"Failed to start '{query}': {e}")

    # Wait for all to complete
    print("\nWaiting for batch completion...")
    completed = 0

    while completed < len(research_ids):
        for research in research_ids:
            if research["status"] != "completed":
                try:
                    status = client.get_research_status(research["id"])
                    if status.get("status") == "completed":
                        research["status"] = "completed"
                        completed += 1
                        print(f"✓ Completed: {research['query']}")
                except Exception:
                    pass

        if completed < len(research_ids):
            time.sleep(3)

    # Get all results
    print("\nBatch Results Summary:")
    for research in research_ids:
        try:
            result = client.get_research_result(research["id"])
            print(f"\n{research['query']}:")
            print(f"  - Summary: {result['summary'][:150]}...")
            print(f"  - Sources: {len(result.get('sources', []))}")
        except Exception as e:
            print(f"  - Error getting results: {e}")


def example_research_history(client: LDRClient) -> None:
    """Example: Viewing research history."""
    print("\n=== Example 5: Research History ===")

    history = client.get_history(limit=5)

    if not history:
        print("No research history found.")
        return

    print(f"Found {len(history)} recent research items:\n")

    for item in history:
        created = item.get("created_at", "Unknown date")
        query = item.get("query", "Unknown query")
        status = item.get("status", "Unknown")
        research_id = item.get("id", item.get("research_id", "N/A"))

        print(f"ID: {research_id}")
        print(f"Query: {query}")
        print(f"Date: {created}")
        print(f"Status: {status}")
        print("-" * 40)


def main():
    """Run all examples."""
    print("=== LDR HTTP API v1.0 Examples ===")
    print(
        "🎯 This example works completely out of the box - no manual setup required!"
    )

    # First, check if server is running
    try:
        response = requests.get(f"{BASE_URL}/auth/check", timeout=5)
        if response.status_code in [
            200,
            401,
        ]:  # 401 is expected when not authenticated
            print("✅ Server is running")
        else:
            print(f"❌ Server returned status code: {response.status_code}")
            print("Make sure the server is running:")
            print("  python -m local_deep_research.web.app")
            return
    except requests.exceptions.ConnectionError:
        print("❌ Cannot connect to LDR server!")
        print("Make sure the server is running:")
        print("  python -m local_deep_research.web.app")
        return

    # Create test user automatically
    username, password = create_test_user()
    if not username:
        print("❌ Failed to create test user")
        return

    # Create client
    client = LDRClient(BASE_URL)

    try:
        # Login with the created user
        print(f"\nLogging in as: {username}")
        if not client.login(username, password):
            print("❌ Login failed!")
            return

        print("✅ Login successful")

        # Check health
        health = client.check_health()
        print(f"Authenticated: {health.get('authenticated', False)}")
        print(f"Username: {health.get('username', 'N/A')}")

        # Run examples
        example_quick_research(client)
        example_detailed_research(client)
        example_settings_management(client)
        example_batch_research(client)
        example_research_history(client)

        print("\n✅ All examples completed successfully!")
        print(f"🔑 Created user: {username}")
        print("📝 You can now use this user for manual testing:")
        print(f"   Username: {username}")
        print(f"   Password: {password}")
        print(f"   Login URL: {BASE_URL}/auth/login")

    except requests.exceptions.ConnectionError:
        print("\n❌ Cannot connect to LDR server!")
        print("Make sure the server is running:")
        print("  python -m local_deep_research.web.app")
    except Exception as e:
        print(f"\n❌ Error: {e}")
    finally:
        # Always logout
        client.logout()
        print("\n✅ Logged out")


if __name__ == "__main__":
    main()
