from __future__ import annotations

import json
import os
from datetime import datetime, timezone
from typing import Any, cast
from urllib.request import Request, urlopen

from investly.domain import Bar, Fundamentals, Market, Quote


class SahmkProvider:
    name = "sahmk"
    base = "https://api.sahmk.sa/api/v1"

    def __init__(self, api_key: str | None = None) -> None:
        key = api_key or os.getenv("SAHMK_API_KEY")
        if not key:
            raise ValueError("SAHMK_API_KEY is required")
        self.api_key: str = key

    def _get(self, path: str) -> dict[str, Any]:
        req = Request(
            f"{self.base}{path}",
            headers={"X-API-Key": self.api_key, "User-Agent": "Investly/0.2"},
        )
        with urlopen(req, timeout=15) as response:
            payload = json.load(response)
        return cast(dict[str, Any], payload)

    def quote(self, market: Market, symbol: str) -> Quote:
        if market != Market.TASI:
            raise ValueError("SAHMK supports Saudi market only")
        d = self._get(f"/quote/{symbol}/")
        updated = d.get("updated_at")
        as_of = (
            datetime.fromisoformat(str(updated).replace("Z", "+00:00"))
            if updated
            else datetime.now(timezone.utc)
        )
        return Quote(
            market=market,
            symbol=str(d.get("symbol", symbol)),
            name=str(d.get("name_en") or d.get("name") or symbol),
            price=float(d["price"]),
            currency="SAR",
            as_of=as_of,
            source=self.name,
            delayed=bool(d.get("is_delayed", True)),
            volume=float(d["volume"]) if d.get("volume") is not None else None,
        )

    def history(self, market: Market, symbol: str, days: int = 260) -> list[Bar]:
        # Historical OHLCV is Starter+. ProviderRouter falls back on Free-plan 403.
        data = self._get(f"/historical/{symbol}/?interval=1d&limit={min(days, 2000)}")
        rows = data.get("data") or data.get("results") or []
        bars: list[Bar] = []
        for raw_row in rows:
            row = cast(dict[str, Any], raw_row)
            ts_raw = row.get("date") or row.get("timestamp")
            if not ts_raw:
                continue
            ts = datetime.fromisoformat(str(ts_raw).replace("Z", "+00:00"))
            bars.append(
                Bar(
                    ts,
                    float(row["open"]),
                    float(row["high"]),
                    float(row["low"]),
                    float(row["close"]),
                    float(row["volume"]),
                )
            )
        return bars[-days:]

    def fundamentals(self, market: Market, symbol: str) -> Fundamentals:
        if market != Market.TASI:
            raise ValueError("SAHMK supports Saudi market only")
        # /company is Free. Starter+ enriches the same response with fundamentals.
        d = self._get(f"/company/{symbol}/")
        values = cast(dict[str, Any], d.get("fundamentals") or {})

        def num(*keys: str) -> float | None:
            for key in keys:
                value = values.get(key)
                if value is not None:
                    try:
                        return float(value)
                    except (TypeError, ValueError):
                        pass
            return None

        return Fundamentals(
            symbol=symbol,
            pe=num("pe_ratio", "pe"),
            pb=num("price_to_book", "pb_ratio", "pb"),
            source=self.name,
            as_of=datetime.now(timezone.utc),
        )
