from __future__ import annotations

import logging

import httpx
import pandas as pd

from config.settings import settings

logger = logging.getLogger(__name__)

VALID_INTERVALS = {"1m", "3m", "5m", "15m", "30m", "1h", "4h", "1d"}
TIMEOUT = 10.0


class KlinesFetcher:
    """
    يجلب بيانات الشمعات من Binance REST API.
    نقطة نهاية عامة — لا تحتاج مفاتيح API.
    """

    def __init__(self) -> None:
        self._client: httpx.AsyncClient | None = None

    async def start(self) -> None:
        self._client = httpx.AsyncClient(
            base_url=settings.BINANCE_BASE_URL,
            timeout=TIMEOUT,
        )
        logger.info(f"KlinesFetcher متصل بـ Binance: {settings.BINANCE_BASE_URL}")

    async def stop(self) -> None:
        if self._client:
            await self._client.aclose()
        logger.info("KlinesFetcher أُغلق")

    async def fetch(
        self,
        symbol: str,
        interval: str | None = None,
        limit: int | None = None,
    ) -> pd.DataFrame:
        """
        يُعيد DataFrame بأعمدة: open_time, open, high, low, close, volume
        مرتبة تصاعدياً بالوقت (الأقدم أولاً — مطلوب لحساب EMA الصحيح).
        """
        interval = interval or settings.DEFAULT_TIMEFRAME
        limit = limit or settings.KLINES_LIMIT

        if interval not in VALID_INTERVALS:
            raise ValueError(
                f"إطار زمني غير صالح: {interval}. المتاح: {VALID_INTERVALS}"
            )

        params = {
            "symbol": symbol.upper(),
            "interval": interval,
            "limit": limit,
        }

        try:
            resp = await self._client.get("/api/v3/klines", params=params)
            resp.raise_for_status()
        except httpx.TimeoutException:
            raise RuntimeError(f"timeout عند جلب {symbol} {interval} من Binance")
        except httpx.HTTPStatusError as e:
            raise RuntimeError(
                f"Binance API خطأ {e.response.status_code}: {e.response.text}"
            )

        raw = resp.json()
        if not raw:
            raise RuntimeError(f"لا توجد بيانات لـ {symbol} {interval}")

        df = pd.DataFrame(raw, columns=[
            "open_time", "open", "high", "low", "close", "volume",
            "close_time", "quote_volume", "trades",
            "taker_buy_base", "taker_buy_quote", "ignore",
        ])

        # الأعمدة المهمة فقط، بالأنواع الصحيحة
        df = df[["open_time", "open", "high", "low", "close", "volume"]].copy()
        for col in ["open", "high", "low", "close", "volume"]:
            df[col] = df[col].astype(float)
        df["open_time"] = pd.to_datetime(df["open_time"], unit="ms")

        # تأكد من الترتيب التصاعدي
        df = df.sort_values("open_time").reset_index(drop=True)

        logger.debug(f"جُلب {len(df)} شمعة لـ {symbol} {interval}")
        return df


fetcher = KlinesFetcher()
