from pathlib import Path
import os
import sys
import re
from cyborgdb_service.core.config import settings


def print_usage_and_exit():
    """Print usage instructions for the CyborgDB Service"""
    print("\n" + "=" * 60)
    print("CyborgDB Service")
    print("=" * 60)

    print("\nUsage: cyborgdb-service [options]")

    print("\nOptions:")
    print("  -init, --init     Initialize the service and install packages")
    print("  --help, -h        Show this help message")

    print("\nExamples:")
    print("  cyborgdb-service -init")
    print("  cyborgdb-service --verbose")

    print("\n" + "=" * 60)
    print("Required Environment Variables:")
    print("=" * 60)
    print("  export CYBORGDB_API_KEY='your_api_key'")

    print("\nOptional Environment Variables (Global Defaults):")
    print("  export CYBORGDB_DB_TYPE='standalone|redis|postgres|memory'")
    print("  export CYBORGDB_CONNECTION_STRING='your_connection_string'")

    print("\nPer-Component Configuration (overrides global defaults):")
    print("  export INDEX_LOCATION='standalone|redis|postgres|memory'")
    print("  export INDEX_CONNECTION_STRING='connection_string'")
    print("  export CONFIG_LOCATION='standalone|redis|postgres|memory'")
    print("  export CONFIG_CONNECTION_STRING='connection_string'")
    print("  export ITEMS_LOCATION='standalone|redis|postgres|memory'")
    print("  export ITEMS_CONNECTION_STRING='connection_string'")

    print("\nDatabase Configuration:")
    print("  Default (no configuration set):")
    print("    - Uses built-in Standalone embedded database")
    print("    - No additional configuration needed")
    print("    - Data stored in ~/.cyborgdb/ (local) or /app/cyborgdb_data/ (Docker)")
    print("    - Perfect for development and testing")

    print("\n  Standalone (location='standalone'):")
    print("    - Connection string is the path to the database directory")
    print('    - Format: "/path/to/standalone/data"')

    print("\n  External Redis (location='redis'):")
    print("    - Requires connection string")
    print('    - Format: "host:localhost,port:6379,db:0"')

    print("\n  PostgreSQL (location='postgres'):")
    print("    - Requires connection string")
    print(
        "    - Format: \"host=localhost port=5432 dbname=dbname user=user password=''\""
    )

    print("\n  In-Memory (location='memory'):")
    print("    - No connection string needed")
    print("    - Data does not persist across restarts")

    print("\n Get your API key: https://cyborgdb.co/")
    print(" Documentation: https://docs.cyborgdb.co/")
    print("")

    sys.exit(0)


def validate_connection_string(
    connection_string: str, db_type: str
) -> tuple[bool, str]:
    """Validate database connection string format without actually connecting"""
    try:
        if db_type.lower() == "redis":
            # Check for URI format (not allowed)
            if connection_string.startswith(("redis://", "rediss://")):
                return (
                    False,
                    "Redis URI format not supported. Use key-value format: host:localhost,port:6379,db:0",
                )

            # Parse redis connection string
            config = {}
            for pair in connection_string.split(","):
                if ":" in pair:
                    key, value = pair.split(":", 1)
                    key = key.strip()
                    value = value.strip()
                    if key in ["port", "db"]:
                        try:
                            config[key] = int(value)
                        except ValueError:
                            return False, f"Invalid {key} value: must be a number"
                    else:
                        config[key] = value

            if "host" not in config or "port" not in config:
                return (
                    False,
                    "Incomplete redis connection string format. 'host' and 'port' are required.",
                )

            if config.get("port", 0) < 1 or config.get("port", 0) > 65535:
                return False, "Invalid port number: must be between 1 and 65535"

            if config.get("db", 0) < 0:
                return False, "Invalid db number: must be non-negative"

            return True, "Connection string format valid"

        elif db_type.lower() == "postgres":
            required = ["host", "port", "dbname"]
            conn_lower = connection_string.lower()

            for keyword in required:
                if f"{keyword}=" not in conn_lower:
                    return False, f"Missing required PostgreSQL parameter: {keyword}"

            port_match = re.search(r"port=(\d+)", connection_string)
            if port_match:
                port = int(port_match.group(1))
                if port < 1 or port > 65535:
                    return False, "Invalid port number: must be between 1 and 65535"

            return True, "Connection string format valid"

        elif db_type.lower() == "rocksdb":
            path_str = connection_string.strip()

            if not path_str:
                return False, "Standalone path cannot be empty string"

            try:
                # Expand user home (~) before validating path syntax
                p = Path(path_str).expanduser()
                p.parts  # validate syntax
            except (ValueError, TypeError):
                return False, "Invalid path syntax"

            # Find the deepest existing ancestor to check permissions
            check_path = (
                p
                if p.exists()
                else next((parent for parent in p.parents if parent.exists()), None)
            )

            if check_path is None:
                return (
                    False,
                    f"No accessible directory found in path: {connection_string}",
                )

            if not check_path.is_dir():
                return False, f"Path exists but is not a directory: {check_path}"

            if not os.access(check_path, os.W_OK | os.R_OK):
                return False, f"Insufficient permissions on: {check_path}"

            return True, "Standalone path format valid"

        else:
            return False, f"Unsupported database type: {db_type}"

    except Exception as e:
        return False, f"Connection string validation failed: {str(e)}"


def print_error_section(title: str, description: str, commands: list[str] | str):
    """Print a formatted error section"""
    print(f"\n\033[91m[ERROR] {title}\033[0m")
    print(f"   {description}")
    if not commands:
        return
    print("\n   Solution:")
    if isinstance(commands, list):
        for cmd in commands:
            print(f"      {cmd}")
    else:
        print(f"      {commands}")


def print_connection_examples():
    """Print detailed connection string examples"""
    print("\n   Examples:")
    print("       PostgreSQL:")
    print(
        "         export CYBORGDB_CONNECTION_STRING=\"host=localhost port=5432 dbname=dbname user=user password=''\""
    )
    print("       Redis:")
    print('         export CYBORGDB_CONNECTION_STRING="host:localhost,port:6379,db:0"')


def ensure_environment_variables():
    """Ensure all required environment variables are set and valid"""
    errors = []

    # Check API key
    if not settings.CYBORGDB_API_KEY:
        errors.append(
            {
                "title": "Missing API Key",
                "description": "CYBORGDB_API_KEY environment variable not set.",
                "solution": "export CYBORGDB_API_KEY='your_api_key_here'",
                "extra": "Get your API key from: https://cyborgdb.co/",
            }
        )

    # Validate connection string formats for redis/postgres/standalone
    # Note: By this point, config.py has already resolved fallbacks and validated
    # that connection strings exist where required. We just check the format here.
    locations_to_check = [
        ("INDEX", settings.INDEX_LOCATION, settings.INDEX_CONNECTION_STRING),
        ("CONFIG", settings.CONFIG_LOCATION, settings.CONFIG_CONNECTION_STRING),
        ("ITEMS", settings.ITEMS_LOCATION, settings.ITEMS_CONNECTION_STRING),
    ]

    for name, location, connection_string in locations_to_check:
        # Only validate format for redis/postgres/standalone (rocksdb)
        if location in ("redis", "postgres", "rocksdb"):
            if location == "rocksdb" and not connection_string:
                # Using default standalone path (handled elsewhere), no string to validate
                success = True
                message = "Using default standalone path"
            elif connection_string:
                success, message = validate_connection_string(
                    connection_string, location
                )
            else:
                success = False
                message = f"{name}_LOCATION is set to '{location}' but no connection string provided."
            if not success:
                errors.append(
                    {
                        "title": f"Invalid {name}_CONNECTION_STRING",
                        "description": message,
                        "solution": [],
                        "show_examples": True,
                    }
                )

    # Print all errors and exit if any
    if errors:
        for error in errors:
            print_error_section(
                error["title"],
                error["description"],
                error.get("solution", []),
            )
            if error.get("extra"):
                print(f"       {error['extra']}")
            if error.get("show_examples"):
                print_connection_examples()

        print(f"\n{'=' * 60}")
        print("  Environment Setup Incomplete")
        print(f"{'=' * 60}")
        print("Please fix the issues above and run again.")
        print("Need help? Check the documentation or contact support.\n")
        sys.exit(1)
