import atexit
import threading
import time
import sys
import traceback
from .models import TraceStep, StepMetrics, StepEvaluation
from .storage import add_step

_original_excepthook = sys.excepthook


def crash_handler(exc_type, exc_value, exc_traceback):
    err_msg = "".join(traceback.format_exception(exc_type, exc_value, exc_traceback))

    # Add a special trace step for the crash
    add_step(
        TraceStep(
            type="server_crash",
            name="Unhandled Exception",
            inputs={
                "type": exc_type.__name__
                if hasattr(exc_type, "__name__")
                else str(exc_type),
                "value": str(exc_value),
            },
            outputs={"traceback": err_msg},
            metrics=StepMetrics(),
            evaluation=StepEvaluation(
                status="error", reasoning="Script terminated unexpectedly."
            ),
        )
    )

    # Call the original hook
    _original_excepthook(exc_type, exc_value, exc_traceback)


def _run_server():
    import uvicorn
    from .server import app

    print(
        "\n✨ AgentTrace: Run complete! Dashboard opened at http://localhost:8000. (Press Ctrl+C to close server and return to terminal)\n"
    )

    def open_browser():
        time.sleep(1.5)
        import webbrowser

        try:
            webbrowser.open("http://localhost:8000")
        except Exception:
            pass

    t = threading.Thread(target=open_browser)
    t.daemon = True
    t.start()

    try:
        uvicorn.run(app, host="127.0.0.1", port=8000, log_level="warning")
    except OSError:
        print(
            "AgentTrace: Dashboard is already running on port 8000 in another process."
        )
    except Exception as e:
        print(f"AgentTrace: Dashboard failed to start: {e}")


def init():
    # Set up OpenTelemetry
    try:
        from opentelemetry import trace
        from opentelemetry.sdk.trace import TracerProvider
        from opentelemetry.sdk.trace.export import SimpleSpanProcessor
        from .exporter import AgentTraceExporter

        provider = TracerProvider()
        provider.add_span_processor(SimpleSpanProcessor(AgentTraceExporter()))
        trace.set_tracer_provider(provider)

        # Auto-instrument OpenTelemetry for OpenAI (also catches Groq since Groq is an OpenAI SDK wrapper)
        try:
            from opentelemetry.instrumentation.openai import OpenAIInstrumentor

            OpenAIInstrumentor().instrument()
        except ImportError:
            pass  # openai extra not installed, skip native OpenAI instrumentation

        # Auto-register external frameworks
        from .integrations import auto_register

        auto_register()
    except ImportError as e:
        import warnings

        warnings.warn(
            f"AgentTrace: OTel dependencies missing ({e}). Native LLM tracing disabled."
        )

    sys.excepthook = crash_handler
    atexit.register(_run_server)


init()
