from .transaction import Transaction, Span
from .context import set_transaction, get_transaction
from .transport import send_payload
import datetime
import traceback
import requests
import threading

DEFAULT_BASE_URL = "https://watchup-server.vercel.app"

class WatchupClient:
    def __init__(self, project_id: str, api_key: str, base_url: str = None):
        self.config = {
            "project_id": project_id,
            "api_key": api_key,
            "base_url": base_url or DEFAULT_BASE_URL
        }
        self.authenticated = False

    def login(self):
        """Perform SDK auth and mark client as initialized."""
        if self.authenticated:
            return

        url = f"{self.config['base_url']}/system/sdk/auth"
        headers = {
            "Content-Type": "application/json",
            "X-Watchup-Project": self.config['project_id'],
            "X-Watchup-Key": self.config['api_key']
        }

        try:
            resp = requests.post(url, headers=headers, json={}, timeout=20)
            resp.raise_for_status()
            self.authenticated = True
        except Exception as e:
            print(f"[WatchupClient] Auth failed: {e}")
            self.authenticated = False

    def start_transaction(self, name: str):
        tx = Transaction(name)
        set_transaction(tx)
        return tx

    def start_span(self, name: str):
        tx = get_transaction()
        if not tx:
            # Fallback for Flask: check request object
            try:
                from flask import request
                tx = getattr(request, "_watchup_tx", None)
            except ImportError:
                pass
        
        if not tx:
            return None
        
        span = Span(name)
        tx.spans.append(span)
        return span

    def capture_transaction(self, tx: Transaction):
        if not tx:
            return

        if not self.authenticated:
            self.login()

        payload = {
            "type": "transaction",
            "name": tx.name,
            "duration_ms": tx.duration,
            "spans": [
                {
                    "name": s.name,
                    "duration_ms": s.duration
                } for s in tx.spans
            ],
            "timestamp": datetime.datetime.now().isoformat()
        }

        send_payload(self.config, payload, endpoint="/v1/capture/transaction")

    def capture_exception(self, exc: Exception, context: dict = None):
        if not self.authenticated:
            self.login()

        context = context or {}
        timestamp = context.get("timestamp")
        started_at = datetime.datetime.now()
        if timestamp:
            try:
                started_at = datetime.datetime.fromisoformat(timestamp)
            except Exception:
                pass

        tx = get_transaction()
        if not tx:
            try:
                from flask import request
                tx = getattr(request, "_watchup_tx", None)
            except ImportError:
                pass
        
        payload = {
            "type": type(exc).__name__,
            "message": str(exc),
            "stack": traceback.format_exc(),
            "componentStack": context.get("componentStack", ""),
            "url": context.get("url", ""),
            "userAgent": context.get("userAgent", ""),
            "transaction": tx.name if tx else None,
            "timestamp": started_at.isoformat()
        }

        # Merge any other custom context if provided
        for key, value in context.items():
            if key not in payload:
                payload[key] = value

        send_payload(self.config, payload, endpoint="/v1/capture")
