"""HTTP helpers for querying the ML-Dash API."""

import requests

from ._errors import MLDashAuthError, MLDashUploadError

# Sent on every SDK request so the backend can identify SDK traffic
# and exempt it from API usage metering.
_SDK_HEADERS = {'X-MLDash-Source': 'sdk'}


def _get(endpoint, url, api_key, params=None):
    """Make an authenticated GET request to ML-Dash."""
    full_url = url.rstrip('/') + endpoint
    headers = {'X-API-Key': api_key, **_SDK_HEADERS}
    try:
        resp = requests.get(full_url, headers=headers, params=params, timeout=15)
    except requests.ConnectionError:
        raise MLDashUploadError(
            f"Could not connect to ML-Dash at {url}. Is the server running?"
        )
    except requests.RequestException as exc:
        raise MLDashUploadError(f"Request failed: {exc}")

    if resp.status_code == 401:
        raise MLDashAuthError("Invalid API key.")
    if resp.status_code == 403:
        raise MLDashAuthError("API key is not authorized.")
    if resp.status_code not in (200, 201):
        try:
            msg = resp.json().get('error') or resp.json().get('detail') or resp.text[:300]
        except Exception:
            msg = resp.text[:300]
        raise MLDashUploadError(f"Server returned {resp.status_code}: {msg}")

    return resp.json()


def fetch_projects(url, api_key):
    """Fetch the user's projects from ML-Dash.

    Returns a list of project dicts with keys: id, name, description,
    model_count, dataset_count, etc.
    """
    data = _get('/api/projects/', url, api_key)
    return data.get('results', [])


def fetch_models(url, api_key, project_id=None):
    """Fetch the user's models from ML-Dash.

    Returns a list of model dicts.
    """
    params = {}
    if project_id is not None:
        params['project'] = str(project_id)
    data = _get('/api/models/', url, api_key, params=params)
    return data.get('results', [])


def fetch_datasets(url, api_key, project_id=None):
    """Fetch the user's datasets from ML-Dash.

    Returns a list of dataset dicts.
    """
    params = {}
    if project_id is not None:
        params['project'] = str(project_id)
    data = _get('/api/datasets/', url, api_key, params=params)
    return data.get('results', [])


def _download(endpoint, url, api_key):
    """Make an authenticated GET request that streams a file download.

    Returns the requests.Response object (not parsed JSON).
    """
    full_url = url.rstrip('/') + endpoint
    headers = {**_SDK_HEADERS, **(({'X-API-Key': api_key} if api_key else {}))}
    try:
        resp = requests.get(full_url, headers=headers, stream=True, timeout=300)
    except requests.ConnectionError:
        raise MLDashUploadError(
            f"Could not connect to ML-Dash at {url}. Is the server running?"
        )
    except requests.RequestException as exc:
        raise MLDashUploadError(f"Request failed: {exc}")

    if resp.status_code == 401:
        raise MLDashAuthError("Authentication required. Run mldash.login() first.")
    if resp.status_code == 403:
        raise MLDashAuthError("Not authorized to access this dataset.")
    if resp.status_code == 404:
        raise MLDashUploadError("Dataset not found.")
    if resp.status_code not in (200, 201):
        raise MLDashUploadError(f"Server returned {resp.status_code}: {resp.text[:300]}")

    return resp


def resolve_project_by_name(url, api_key, name):
    """Look up a project by name or slug. Returns the project ID or None."""
    projects = fetch_projects(url, api_key)
    for p in projects:
        if p['name'] == name or p.get('slug') == name:
            return p['id']
    return None
