"""
Public API surface — module-level functions that delegate to the global client.

All functions are safe to call even before ``init()`` (they silently no-op).
"""

import sys
import atexit

from overcast_sdk.consts import SDK_VERSION
from overcast_sdk.utils import capture_internal, debug_log
from overcast_sdk.client import OvercastClient, get_client, set_client
from overcast_sdk.scope import get_current_scope, get_global_scope
from overcast_sdk.integrations import setup_integrations

_initialized = False


# ═══════════════════════════════════════════════════════════════════════════════
# Initialisation
# ═══════════════════════════════════════════════════════════════════════════════

def init(api_key="", service_name="python-app", **kwargs):
    """Initialise the Overcast SDK.  Call once at application startup.

    Args:
        api_key:      Your Overcast API key (required).
        service_name: Service name shown in the dashboard.
        **kwargs:     Any other configuration options (see ``consts.DEFAULT_OPTIONS``).
    """
    global _initialized

    if _initialized:
        debug_log("Already initialised, skipping.")
        return

    # Allow env-var fallback
    import os
    if not api_key:
        api_key = os.environ.get("OVERCAST_API_KEY", "")
    if not service_name:
        service_name = os.environ.get("OVERCAST_SERVICE_NAME", "python-app")

    # Build options dict
    options = dict(kwargs)
    options["api_key"] = api_key
    options["service_name"] = service_name

    # Create client (validates options)
    try:
        client = OvercastClient(options)
    except ValueError as exc:
        print(f"[Overcast] {exc}", file=sys.stderr)
        return

    set_client(client)
    _initialized = True

    # Set up auto-discovered integrations (logging, stdlib, requests, httpx)
    with capture_internal:
        setup_integrations(client.options, explicit=options.get("integrations"))

    # Flush on exit
    atexit.register(shutdown)

    debug_log(
        f'Initialised for service "{service_name}" '
        f'in {client.options["environment"]}'
    )

    # Init heartbeat — flush immediately so the wizard can verify installation
    client.enqueue("INFO", "Overcast SDK initialized", {
        "type": "sdk_init",
        "sdk_version": SDK_VERSION,
        "python_version": sys.version,
        "platform": sys.platform,
    })
    client.flush(timeout=3.0)


# ═══════════════════════════════════════════════════════════════════════════════
# Manual logging
# ═══════════════════════════════════════════════════════════════════════════════

def error(message, **metadata):
    """Log an error."""
    client = get_client()
    if client:
        client.enqueue("ERROR", str(message), {**metadata, "type": "manual"})


def warn(message, **metadata):
    """Log a warning."""
    client = get_client()
    if client:
        client.enqueue("WARNING", str(message), {**metadata, "type": "manual"})


def info(message, **metadata):
    """Log an informational message."""
    client = get_client()
    if client:
        client.enqueue("INFO", str(message), {**metadata, "type": "manual"})


def debug(message, **metadata):
    """Log a debug message."""
    client = get_client()
    if client:
        client.enqueue("DEBUG", str(message), {**metadata, "type": "manual"})


def capture_exception(exc, **metadata):
    """Capture an exception manually."""
    client = get_client()
    if client:
        client.capture_exception(exc, **metadata)


# ═══════════════════════════════════════════════════════════════════════════════
# Scope helpers
# ═══════════════════════════════════════════════════════════════════════════════

def set_tag(key, value):
    """Set a tag on the current (isolation) scope."""
    get_current_scope().set_tag(key, value)


def set_user(user_data):
    """Set user context on the current (isolation) scope."""
    get_current_scope().set_user(user_data)


def set_extra(key, value):
    """Set extra data on the current (isolation) scope."""
    get_current_scope().set_extra(key, value)


def set_context(key, value):
    """Set a named context block on the current (isolation) scope."""
    get_current_scope().set_context(key, value)


def add_breadcrumb(crumb, hint=None):
    """Add a breadcrumb to the current (isolation) scope."""
    get_current_scope().add_breadcrumb(crumb, hint)


# ═══════════════════════════════════════════════════════════════════════════════
# Flush / shutdown
# ═══════════════════════════════════════════════════════════════════════════════

def flush(timeout=5.0):
    """Flush all buffered events to the server."""
    client = get_client()
    if client:
        client.flush(timeout)


def shutdown():
    """Flush remaining events and tear down the SDK."""
    global _initialized
    client = get_client()
    if client:
        with capture_internal:
            client.close()
        set_client(None)
    _initialized = False
    debug_log("Shutdown complete.")


# ═══════════════════════════════════════════════════════════════════════════════
# OOP convenience class
# ═══════════════════════════════════════════════════════════════════════════════

class Overcast:
    """Static-method wrapper providing an OOP-style interface."""

    init = staticmethod(init)
    error = staticmethod(error)
    warn = staticmethod(warn)
    info = staticmethod(info)
    debug = staticmethod(debug)
    capture_exception = staticmethod(capture_exception)
    set_tag = staticmethod(set_tag)
    set_user = staticmethod(set_user)
    set_extra = staticmethod(set_extra)
    set_context = staticmethod(set_context)
    add_breadcrumb = staticmethod(add_breadcrumb)
    flush = staticmethod(flush)
    shutdown = staticmethod(shutdown)
