"""Wirelytics API — minimal client (Python 3.8+, standard library only).

    WIRELYTICS_API_KEY=wlx_live_… python wirelytics.py CRML            one brief
    WIRELYTICS_API_KEY=wlx_live_… python wirelytics.py CRML ALIT UURAF  batch

Server-side only: never ship your API key to a browser.
Docs: https://www.wirelytics.de/integration
"""

import json
import os
import sys
import urllib.error
import urllib.parse
import urllib.request

BASE = os.environ.get("WIRELYTICS_BASE_URL", "https://api.wirelytics.de")


class WirelyticsError(Exception):
    def __init__(self, status, body, retry_after=None):
        self.status = status                # 400 · 401 · 403 · 404 · 429 · 500
        self.code = body.get("error")       # e.g. "not_found", "rate_limited"
        self.body = body
        self.retry_after = retry_after      # 429 only: seconds until the quota resets (UTC midnight)
        hint = f" – {body['hint']}" if body.get("hint") else ""
        super().__init__(f"{status} {self.code}{hint}")


def call(api_key, params):
    url = f"{BASE}/brief-api?{urllib.parse.urlencode(params)}"
    req = urllib.request.Request(url, headers={"Authorization": f"Bearer {api_key}"})
    try:
        with urllib.request.urlopen(req, timeout=30) as res:
            raw = res.read().decode("utf-8")
            is_json = "json" in res.headers.get("content-type", "")
            return json.loads(raw) if is_json else raw
    except urllib.error.HTTPError as e:
        raw = e.read().decode("utf-8")
        try:
            body = json.loads(raw)
        except ValueError:
            body = {"error": raw}
        retry = e.headers.get("retry-after")
        raise WirelyticsError(e.code, body, int(retry) if retry else None) from None


def get_brief(api_key, ticker, date=None, fmt=None):
    """Newest brief of one ticker (last 30 days). date → archive;
    fmt "meta" (light) or "html"/"markdown" (ready-to-embed text)."""
    params = {"ticker": ticker}
    if date:
        params["date"] = date
    if fmt:
        params["format"] = fmt
    return call(api_key, params)


def get_batch(api_key, tickers, date=None, include_edition=False):
    """Up to 50 tickers, sorted by score. Entries with missing=True (no brief)
    or denied=True (outside your coverage set) carry no analysis."""
    params = {"tickers": ",".join(tickers)}
    if date:
        params["date"] = date
    if include_edition:
        params["include"] = "edition"
    return call(api_key, params)


if __name__ == "__main__":
    # Windows consoles default to a legacy code page; print · and – correctly.
    if hasattr(sys.stdout, "reconfigure"):
        sys.stdout.reconfigure(encoding="utf-8")
        sys.stderr.reconfigure(encoding="utf-8")
    key = os.environ.get("WIRELYTICS_API_KEY")
    args = [t.upper() for t in sys.argv[1:]]
    if not key or not args:
        sys.exit("usage: WIRELYTICS_API_KEY=… python wirelytics.py TICKER [TICKER …]")
    try:
        if len(args) == 1:
            d = get_brief(key, args[0])["data"]
            v = d["verdict"]
            print(f"{d['name']} ({d['ticker']}) · {d['brief_date']} · "
                  f"Score {v['score']}/10 · {v['rating']} · Risiko {v['risk_level']}")
            print((d.get("narrative") or {}).get("signal_driver") or "")
        else:
            for b in get_batch(key, args)["data"]:
                if b.get("missing"):
                    print(f"{b['ticker']:<8} – kein Brief ({b['reason']})")
                elif b.get("denied"):
                    print(f"{b['ticker']:<8} – nicht in deinem Plan")
                else:
                    print(f"{b['ticker']:<8} {b['verdict']['score']:>4}  {b['verdict']['rating']}")
    except WirelyticsError as e:
        wait = f" (Kontingent wieder frei in {e.retry_after // 60} min)" if e.retry_after else ""
        sys.exit(f"API-Fehler {e}{wait}")
