from __future__ import annotations

from dataclasses import dataclass
import os
from typing import Any, Dict


def _env(name: str, default: str) -> str:
    v = os.getenv(name, "").strip()
    return v or default


def _env_float(name: str, default: float) -> float:
    v = os.getenv(name, "").strip()
    if not v:
        return float(default)
    try:
        return float(v)
    except Exception:
        return float(default)


@dataclass(frozen=True)
class ServiceConfig:
    hardware: str
    interp: str
    analysis: str


SERVICES = ServiceConfig(
    hardware=_env("HARDWARE_BASE_URL", "http://127.0.0.1:8000"),
    interp=_env("INTERP_BASE_URL", "http://127.0.0.1:7475"),
    analysis=_env("ANALYSIS_BASE_URL", "http://127.0.0.1:1717"),
)

HARDWARE_BASE_URL: str = SERVICES.hardware
INTERP_BASE_URL: str = SERVICES.interp
ANALYSIS_BASE_URL: str = SERVICES.analysis
BASE_URL: str = HARDWARE_BASE_URL

HTTP_TIMEOUT_SEC: float = _env_float("HTTP_TIMEOUT_SEC", 5.0)


ENDPOINTS: Dict[str, Any] = {
    # -----------------------------
    # scanner / systems / sequences
    # -----------------------------
    "sequence_params": "/sequence/params",  # POST sequence params JSON
    "sequence_interpret": {
        "interpret": "/interpret/",  # POST multipart file (.seq)
        "status": "/status/",        # GET status of interpretation tasks
    },

    "systems": {
        "gradient": {
            "health": "/systems/gradient/health",        # GET
            "upload_config": "/systems/gradient/config", # POST multipart file
            "start": "/systems/gradient/start",          # POST
        },
        "rf": {
            "health": "/systems/rf/health",
            "upload_config": "/systems/rf/config",
            "start": "/systems/rf/start",
        },
        "adc": {
            "health": "/systems/adc/health",
            "upload_config": "/systems/adc/config",
            "start": "/systems/adc/start",
        },
    },

    "scan": {
        # Real spectrometer service API (measurement-based)
        "start": "/api/measurement",                       # POST (or GET fallback) -> measurement id
        "start_fallback_get": "/api/measurement",          # GET starts measurement on some deployments
        "state_by_id": "/api/measurement/{scan_id}/state", # GET
        "data_by_id": "/api/measurement/{scan_id}/data",   # GET
        "state": "/api/mstate",                            # GET optional legacy state endpoint
        # Backward compatibility for older backend shape
        "progress": "/scan/progress",                      # GET params: scan_id=...
        "stop": "/scan/stop",                              # POST optional
    },

    # -----------------------------
    # ANALYSIS
    # -----------------------------
    "analysis": {
        "upload": "/upload/",          # POST multipart
        "filter": "/filter/",          # POST form
        "fft": "/fft/",                # POST form
        "result": "/result/",          # GET params session_id
        "export": "/export/",          # POST form
        "plot_raw": "/plot-raw/",      # POST form
        # readme_spectrum endpoints
        "export_raw_data": "/export-raw-data/",                    # POST form
        "export_filter_data": "/export-filter-data/",              # POST form
        "export_decdem_data": "/export-decdem-data/",              # POST form
        "export_position_freq": "/export-position-freq/",          # POST form
        "export_fwhm": "/export-FWHM/",                            # POST form
        "export_max_amplitude_freq": "/export-max-amplitude-freq/",# POST form
    },
}


def join_url(base_url: str, path: str) -> str:
    b = (base_url or "").rstrip("/")
    p = (path or "")
    if not p.startswith("/"):
        p = "/" + p
    return b + p


def build_url(service: str, path: str) -> str:
    base = getattr(SERVICES, service)
    return join_url(base, path)


def get_endpoint(*keys: str) -> str:
    """Resolve endpoint path from ENDPOINTS by keys.

    Examples:
        get_endpoint("sequence_params")
        get_endpoint("systems", "gradient", "health")
        get_endpoint("analysis", "upload")
    """
    cur: Any = ENDPOINTS
    for k in keys:
        cur = cur[k]
    if not isinstance(cur, str):
        raise TypeError(f"Endpoint {keys} resolved to non-string: {type(cur)}")
    return cur
