"""
GHL API Client with OAuth Token Management

Drop-in replacement for raw API calls. Automatically selects
the right token per location and handles refresh.

Usage:
    from GHL.oauth.ghl_client import GHLClient

    client = GHLClient()

    # Get contacts for SA-008
    contacts = client.get("contacts/", location_id="7UExU3gWmZqJEKbAeAq4")

    # Create a custom field in SA-002
    client.post("locations/7pC1NP1LxO736KU267N4/customFields", json={...})
"""

import sys
import logging
from typing import Optional, Dict, Any

import requests

sys.path.append("/mnt/e/genesis-system/data/genesis-memory")
sys.path.append("/mnt/e/genesis-system")

from GHL.oauth.config import GHLOAuthConfig
from GHL.oauth.token_vault import TokenVault

logger = logging.getLogger(__name__)


class GHLClient:
    """Authenticated GHL API client using OAuth tokens per location."""

    def __init__(self, config: GHLOAuthConfig = None, vault: TokenVault = None):
        self.config = config or GHLOAuthConfig()
        self.vault = vault or TokenVault(self.config)
        self._session = requests.Session()

    def get(self, endpoint: str, location_id: Optional[str] = None,
            params: Optional[dict] = None) -> Dict[str, Any]:
        return self._request("GET", endpoint, location_id, params=params)

    def post(self, endpoint: str, location_id: Optional[str] = None,
             json: Optional[dict] = None, data: Optional[dict] = None) -> Dict[str, Any]:
        return self._request("POST", endpoint, location_id, json=json, data=data)

    def put(self, endpoint: str, location_id: Optional[str] = None,
            json: Optional[dict] = None) -> Dict[str, Any]:
        return self._request("PUT", endpoint, location_id, json=json)

    def delete(self, endpoint: str, location_id: Optional[str] = None) -> Dict[str, Any]:
        return self._request("DELETE", endpoint, location_id)

    def _request(self, method: str, endpoint: str, location_id: Optional[str] = None,
                 **kwargs) -> Dict[str, Any]:
        """Make an authenticated API request."""
        # Get the right token
        if location_id:
            access_token = self.vault.get_valid_token(location_id)
            if not access_token:
                return {
                    "error": f"No valid token for location {location_id}",
                    "status": "auth_error",
                    "hint": "Run: python3 GHL/oauth/setup.py --exchange-all",
                }
        else:
            # Use agency token for agency-level endpoints
            agency = self.vault.get_agency_token()
            if not agency:
                return {
                    "error": "No agency token available",
                    "status": "auth_error",
                    "hint": "Run: python3 GHL/oauth/setup.py --init-flow",
                }
            if agency.needs_refresh:
                agency = self.vault.refresh_agency_token()
            access_token = agency.access_token if agency else None
            if not access_token:
                return {"error": "Agency token refresh failed", "status": "auth_error"}

        # Build URL
        url = endpoint if endpoint.startswith("http") else f"{self.config.api_base_url}/{endpoint.lstrip('/')}"

        headers = {
            "Authorization": f"Bearer {access_token}",
            "Version": self.config.api_version,
            "Content-Type": "application/json",
        }

        try:
            resp = self._session.request(method, url, headers=headers, timeout=30, **kwargs)

            if resp.status_code == 401:
                # Token might have been invalidated — try re-exchange
                if location_id:
                    logger.warning(f"401 for {location_id}, re-exchanging token")
                    self.vault.exchange_location_token(location_id)
                    new_token = self.vault.get_valid_token(location_id)
                    if new_token:
                        headers["Authorization"] = f"Bearer {new_token}"
                        resp = self._session.request(method, url, headers=headers, timeout=30, **kwargs)

            return {
                "status_code": resp.status_code,
                "data": resp.json() if resp.content else {},
                "ok": 200 <= resp.status_code < 300,
            }

        except requests.RequestException as e:
            logger.error(f"GHL API error: {e}")
            return {"error": str(e), "status": "network_error"}

    def list_locations(self) -> list:
        """List all sub-accounts accessible via the agency token."""
        result = self.get(
            f"locations/search?companyId={self.config.company_id}"
        )
        if result.get("ok"):
            return result["data"].get("locations", [])
        return []

    def test_location_access(self, location_id: str) -> Dict[str, Any]:
        """Test if we can access a location's resources."""
        tests = {}
        endpoints = [
            ("custom_fields", f"locations/{location_id}/customFields"),
            ("tags", f"locations/{location_id}/tags"),
            ("contacts", f"contacts/?locationId={location_id}&limit=1"),
            ("calendars", f"calendars/?locationId={location_id}"),
        ]

        for name, endpoint in endpoints:
            result = self.get(endpoint, location_id=location_id)
            tests[name] = {
                "status_code": result.get("status_code"),
                "ok": result.get("ok", False),
            }

        return {
            "location_id": location_id,
            "tests": tests,
            "all_pass": all(t["ok"] for t in tests.values()),
        }
