import asyncio
import time
import aiohttp
from aiohttp import ClientError
from sds_mng.util import logger

API_URL = "https://pod-api.sdspod.com/pod/orders/page"
REQUEST_TIMEOUT = 30
DEFAULT_SLEEP = 5
DEFAULT_CONCURRENCY = 5


async def _fetch(access_token, filters=None, sleep=DEFAULT_SLEEP):
    headers = {"access-token": access_token}
    page = filters.get("page", 1) if filters else 1
    size = filters.get("size", 100) if filters else 100
    order_status_code = filters.get("orderStatusCode") if filters else None
    filter_dict = {k: v for k, v in filters.items() if k not in {"page", "size", "orderStatusCode"}} if filters else {}

    params = {
        "orderTimeRangeType": "2",
        "productionType": "2",
        "page": page,
        "size": size,
        "t": int(time.time() * 1000),
    }
    if order_status_code is not None:
        params["orderStatusCode"] = order_status_code
    if filter_dict:
        params.update(filter_dict)

    for attempt in range(1, 4):  # 最多重试3次
        try:
            async with aiohttp.ClientSession() as session:
                async with session.get(
                    API_URL, headers=headers, params=params,
                    timeout=aiohttp.ClientTimeout(total=REQUEST_TIMEOUT)
                ) as resp:
                    resp.raise_for_status()
                    data = await resp.json()
                    logger.info(f"获取到 {len(data.get('list', []))} 条订单，总计 {data.get('totalCount', 0)} 条")
                    await asyncio.sleep(sleep)
                    return data
        except ClientError as e:
            # 如果响应中包含"用户未登录"则直接抛出
            if hasattr(e, "response") and e.response is not None:
                try:
                    error_json = await e.response.json()
                    if error_json.get("msg") == "用户未登录":
                        raise
                except Exception:
                    pass
            if attempt == 3:
                raise
            await asyncio.sleep(2 ** (attempt - 1))


async def fetch_orders(access_token, filters=None, limit=None, concurrency=DEFAULT_CONCURRENCY, sleep=DEFAULT_SLEEP):
    first_page_data = await _fetch(access_token, {**(filters or {}), "page": 1, "size": 100}, sleep)
    total = first_page_data.get("totalCount", 0)
    orders = first_page_data.get("list", [])

    if limit is not None and limit <= len(orders):
        return {"totalCount": total, "fetchedCount": len(orders[:limit]), "list": orders[:limit]}

    pages_needed = (limit - len(orders) + 99) // 100 if limit is not None else (total + 99) // 100 - 1
    page_numbers = list(range(2, min((total + 99) // 100, 2 + pages_needed - 1) + 1))

    semaphore = asyncio.Semaphore(concurrency)
    async def fetch_page(page):
        async with semaphore:
            return await _fetch(access_token, {**(filters or {}), "page": page, "size": 100}, sleep)

    results = await asyncio.gather(*[fetch_page(p) for p in page_numbers])
    for data in results:
        orders.extend(data.get("list", []))
        if limit is not None and len(orders) >= limit:
            break

    if limit is not None:
        orders = orders[:limit]
    return {"totalCount": total, "fetchedCount": len(orders), "list": orders}