import asyncio
import time
import aiohttp
from aiohttp import ClientError
from tenacity import (
    retry,
    stop_after_attempt,
    wait_exponential,
    retry_if_exception_type,
)
from sds_mng.util import logger, raise_for_status

REQUEST_TIMEOUT = 30
DEFAULT_SLEEP = 5
MAX_SIZE = 200
DEFAULT_CONCURRENCY = 5


async def fetch_id(token):
    url = "https://pod-api.sdspod.com/pod/issuing_bay_areas"
    params = {"t": str(int(time.time() * 1000))}
    headers = {
        "access-token": token or "",
    }

    async with aiohttp.ClientSession() as session:
        async with session.get(url, params=params, headers=headers) as resp:
            data = await resp.json()
            raise_for_status(resp, data)
            logger.debug(data)
            return {
                item.get("name", ""): item.get("id", "")
                for item in data.get("items", [])
            }


@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=1, max=8),
    retry=retry_if_exception_type(ClientError),
)
async def _fetch(
    token: str,
    area_id: int,
    page: int,
    sleep=DEFAULT_SLEEP,
    sem: asyncio.Semaphore = None,
):
    async with sem:
        url = "https://pod-api.sdspod.com/pod/logistics/page"
        headers = {
            "access-token": token,
        }
        params = {
            "keyword": "",
            "deliveryMethod": "FBM",
            "issuingBayAreaId": area_id,
            "page": page,
            "size": MAX_SIZE,
            "t": str(int(time.time() * 1000)),
        }
        async with aiohttp.ClientSession() as session:
            async with session.get(url, params=params, headers=headers) as resp:
                data = await resp.json()
                raise_for_status(resp, data)
                await asyncio.sleep(sleep)
                return data


async def fetch_logistics(
    token: str,
    area_id: str,
    limit=None,
    concurrency=DEFAULT_CONCURRENCY,
    sleep=DEFAULT_SLEEP,
):
    sem = asyncio.Semaphore(concurrency)

    first = await _fetch(token, area_id, 1, sleep, sem)
    total, items = first.get("totalCount", 0), first.get("items", [])
    target = limit or total

    if limit and limit <= len(items):
        logger.info(f"已获取 {limit}/{target} 条数据")
        return {
            "totalCount": total,
            "fetchedCount": limit,
            "list": items[:limit],
        }

    needed = limit or total
    needed_pages = (needed + MAX_SIZE - 1) // MAX_SIZE
    if needed_pages <= 1:
        logger.info(f"已获取 {len(items)}/{target} 条数据")
        return {
            "totalCount": total,
            "fetchedCount": len(items),
            "list": items,
        }

    pages = list(range(2, needed_pages + 1))
    tasks = [_fetch(token, area_id, p, sleep, sem) for p in pages]

    for coro in asyncio.as_completed(tasks):
        data = await coro
        items.extend(data.get("items", []))
        logger.info(f"已获取 {len(items)}/{target} 条数据")

    fetched = limit or len(items)
    logger.info(f"已获取 {fetched}/{target} 条数据")
    return {
        "totalCount": total,
        "fetchedCount": fetched,
        "list": items[:limit] if limit else items,
    }
