"""
Auth client — calls the SigmanticAI Gateway API for all auth operations.

NO Supabase SDK, NO direct DB access, NO Stripe secrets.
The client only:
  1. Stores tokens locally (credentials.py)
  2. Calls the gateway REST API for auth/quota/billing

Gateway endpoints used:
  POST /v1/auth/login       — email/password login
  POST /v1/auth/refresh     — refresh token
  GET  /v1/auth/me          — verify token + user info
  GET  /v1/auth/quota       — check quota
  POST /v1/auth/usage       — increment usage
"""

from __future__ import annotations

import json
import logging
import os
import ssl
import time
import urllib.error
import urllib.request
from typing import Any, Dict, Optional

import certifi

from sigmanticai.auth.credentials import (
    save_credentials,
    load_credentials,
)

logger = logging.getLogger("sigmanticai.auth")

# ── API base URL ─────────────────────────────────────────────
# For prod: https://api.sigmanticai.com  (or ALB URL)
# For local dev: http://localhost:8000
# The gateway serves both WebSocket (/v1/ws) and REST (/v1/auth/*)
_DEFAULT_API_URL = "https://api.sigmanticai.com"
API_BASE_URL = os.environ.get("SIGMANTICAI_API_URL", _DEFAULT_API_URL)

# Strip trailing slashes and /v1/ws if user passed a WebSocket URL
if API_BASE_URL.startswith("ws://"):
    API_BASE_URL = API_BASE_URL.replace("ws://", "http://", 1)
elif API_BASE_URL.startswith("wss://"):
    API_BASE_URL = API_BASE_URL.replace("wss://", "https://", 1)
if API_BASE_URL.endswith("/v1/ws"):
    API_BASE_URL = API_BASE_URL[:-6]
API_BASE_URL = API_BASE_URL.rstrip("/")


# ── HTTP helpers ─────────────────────────────────────────────

def _api_request(
    method: str,
    path: str,
    *,
    body: Optional[Dict[str, Any]] = None,
    token: Optional[str] = None,
    timeout: int = 15,
) -> Dict[str, Any]:
    """Make an HTTP request to the gateway API.

    Raises urllib.error.HTTPError on 4xx/5xx.
    """
    url = f"{API_BASE_URL}{path}"
    data = json.dumps(body).encode() if body else None

    headers: Dict[str, str] = {"Content-Type": "application/json"}
    if token:
        headers["Authorization"] = f"Bearer {token}"

    ssl_ctx = ssl.create_default_context(cafile=certifi.where())
    req = urllib.request.Request(url, data=data, headers=headers, method=method)
    with urllib.request.urlopen(req, timeout=timeout, context=ssl_ctx) as resp:
        return json.loads(resp.read())


# ── Token management ─────────────────────────────────────────

def get_access_token() -> Optional[str]:
    """
    Get a valid access token from stored credentials.

    If the token is older than 50 minutes, refreshes it via the gateway API.
    Returns None if not logged in.
    """
    creds = load_credentials()
    if not creds:
        return None

    access_token = creds.get("access_token")
    refresh_token = creds.get("refresh_token")
    timestamp = creds.get("timestamp", 0)

    # If token is older than 50 minutes, try to refresh via API
    if time.time() - timestamp > 3000 and refresh_token:
        try:
            data = _api_request("POST", "/v1/auth/refresh", body={
                "refresh_token": refresh_token,
            })
            new_creds = {
                "access_token": data["access_token"],
                "refresh_token": data["refresh_token"],
                "timestamp": time.time(),
            }
            save_credentials(new_creds)
            return new_creds["access_token"]
        except urllib.error.HTTPError as e:
            if e.code in (401, 403):
                # Auth/ban rejection — do NOT fall back to old token.
                # Clear credentials so user is forced to re-login.
                logger.warning("Token refresh rejected (HTTP %d): %s", e.code, e)
                from sigmanticai.auth.credentials import clear_credentials
                clear_credentials()
                return None
            # Other HTTP errors (500, 503) — server issue, fall back to existing token
            logger.warning("Token refresh failed (HTTP %d, will use existing token): %s", e.code, e)
        except Exception as e:
            # Network error — fall back to existing token
            logger.warning("Token refresh via API failed (will use existing token): %s", e)

    return access_token


# ── Auth operations (all go through gateway API) ─────────────

class AuthClient:
    """Client for gateway auth API.

    All operations call the gateway REST API — no direct Supabase access.
    """

    def verify_token(self, access_token: str) -> Dict[str, Any]:
        """Verify token + get user info via gateway API."""
        return _api_request("GET", "/v1/auth/me", token=access_token)

    def check_quota(self, access_token: str) -> Dict[str, Any]:
        """Check generation quota via gateway API.

        Returns dict with keys: allowed, used, max, remaining, plan.
        """
        return _api_request("GET", "/v1/auth/quota", token=access_token)

    def increment_usage(self, access_token: str) -> None:
        """Increment usage after a successful generation."""
        _api_request("POST", "/v1/auth/usage", token=access_token)

    def login(self, email: str, password: str) -> Dict[str, Any]:
        """Login via gateway API (not directly to Supabase)."""
        data = _api_request("POST", "/v1/auth/login", body={
            "email": email,
            "password": password,
        })
        creds = {
            "access_token": data["access_token"],
            "refresh_token": data["refresh_token"],
            "timestamp": time.time(),
        }
        save_credentials(creds)
        return creds

    def send_otp(self, email: str) -> Dict[str, Any]:
        """Request a one-time verification code sent to the user's email."""
        return _api_request("POST", "/v1/auth/otp/send", body={"email": email})

    def verify_otp(self, email: str, token: str) -> Dict[str, Any]:
        """Verify the OTP code and save credentials."""
        data = _api_request("POST", "/v1/auth/otp/verify", body={
            "email": email,
            "token": token,
        })
        creds = {
            "access_token": data["access_token"],
            "refresh_token": data["refresh_token"],
            "timestamp": time.time(),
        }
        save_credentials(creds)
        return creds

