"""SDK-style QSentia Connect client example.

Set QSENTIA_CONNECT_API_KEY before running:
  export QSENTIA_CONNECT_API_KEY="qs_sandbox_..."

Optional:
  export QSENTIA_CONNECT_BASE_URL="https://www.qsentia.com"
  export QSENTIA_CONNECT_MODEL_ID="brppo_crypto"
  export QSENTIA_CONNECT_CUSTOM_CANDIDATE_ID="candidate_..."
"""

from __future__ import annotations

import hashlib
import hmac
import json
import os
import sys
import urllib.error
import urllib.request
from dataclasses import dataclass
from typing import Any


@dataclass(frozen=True)
class QSentiaConnectClient:
    api_key: str
    base_url: str = "https://www.qsentia.com"

    def _request(self, method: str, path: str, payload: dict[str, Any] | None = None) -> dict[str, Any]:
        if not self.api_key:
            raise RuntimeError("QSENTIA_CONNECT_API_KEY is required")

        body = None if payload is None else json.dumps(payload).encode("utf-8")
        request = urllib.request.Request(
            f"{self.base_url.rstrip('/')}{path}",
            data=body,
            method=method,
            headers={
                "Authorization": f"Bearer {self.api_key}",
                "Accept": "application/json",
                "Content-Type": "application/json",
                "User-Agent": "qsentia-connect-python-sdk-example/1.0",
            },
        )

        try:
            with urllib.request.urlopen(request, timeout=20) as response:
                return json.loads(response.read().decode("utf-8"))
        except urllib.error.HTTPError as exc:
            error_body = exc.read().decode("utf-8", errors="replace")
            raise RuntimeError(f"QSentia Connect request failed: HTTP {exc.code} {error_body}") from exc

    def list_models(self) -> dict[str, Any]:
        return self._request("GET", "/api/connect/v1/models")

    def latest_signal(self, model_id: str) -> dict[str, Any]:
        return self._request("GET", f"/api/connect/v1/models/{model_id}/latest-signal")

    def list_custom_models(self) -> dict[str, Any]:
        return self._request("GET", "/api/connect/v1/custom-models")

    def custom_model(self, candidate_id: str) -> dict[str, Any]:
        return self._request("GET", f"/api/connect/v1/custom-models/{candidate_id}")

    def custom_model_backtest(self, candidate_id: str) -> dict[str, Any]:
        return self._request("GET", f"/api/connect/v1/custom-models/{candidate_id}/backtest")

    def custom_model_latest_signal(self, candidate_id: str) -> dict[str, Any]:
        return self._request("GET", f"/api/connect/v1/custom-models/{candidate_id}/latest-signal")

    def list_webhooks(self) -> dict[str, Any]:
        return self._request("GET", "/api/connect/v1/webhooks")

    def register_webhook(self, url: str, event_types: list[str] | None = None) -> dict[str, Any]:
        return self._request(
            "POST",
            "/api/connect/v1/webhooks",
            {
                "label": "Primary receiver",
                "url": url,
                "eventTypes": event_types or ["model.signal.created", "model.telemetry.updated", "connect.test"],
                "environment": "sandbox",
            },
        )

    def send_test_webhook(self) -> dict[str, Any]:
        return self._request("POST", "/api/connect/v1/webhooks/test", {"eventType": "connect.test"})


def verify_webhook_signature(signing_secret: str, timestamp: str, raw_body: bytes, signature_header: str) -> bool:
    """Validate X-QSentia-Signature formatted as: t=<timestamp>,v1=<hex_digest>."""
    expected = hmac.new(signing_secret.encode("utf-8"), timestamp.encode("utf-8") + b"." + raw_body, hashlib.sha256).hexdigest()
    received = ""
    for item in signature_header.split(","):
        key, _, value = item.partition("=")
        if key == "v1":
            received = value
            break
    return bool(received) and hmac.compare_digest(expected, received)


def main() -> int:
    client = QSentiaConnectClient(
        api_key=os.environ.get("QSENTIA_CONNECT_API_KEY", ""),
        base_url=os.environ.get("QSENTIA_CONNECT_BASE_URL", "https://www.qsentia.com"),
    )
    model_id = os.environ.get("QSENTIA_CONNECT_MODEL_ID", "brppo_crypto")
    custom_candidate_id = os.environ.get("QSENTIA_CONNECT_CUSTOM_CANDIDATE_ID", "")

    print(json.dumps(client.list_models(), indent=2))
    print(json.dumps(client.latest_signal(model_id), indent=2))
    print(json.dumps(client.list_custom_models(), indent=2))
    if custom_candidate_id:
        print(json.dumps(client.custom_model_latest_signal(custom_candidate_id), indent=2))
        print(json.dumps(client.custom_model_backtest(custom_candidate_id), indent=2))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
