import asyncio
import os
from pathlib import Path
from datetime import datetime, time

import redis.asyncio as redis
from loguru import logger
from curl_cffi.requests import AsyncSession, Response

IS_DEBUG = int(os.environ.get("IS_DEBUG", False))
LOG_PATH = f"./log/{Path(__file__).stem}.log"
if not IS_DEBUG:
    logger.remove()
logger.add(LOG_PATH, level="INFO", rotation="1 day", retention="1 months")


class Subsidiary:
    def __init__(self):
        self._tasks = []
        self.s = AsyncSession()
        self.r: redis.Redis = None

    async def connect(self):
        if self.r is None:
            self.r = redis.Redis(
                host="localhost",
                port=int(os.getenv("REDIS_HOST", 6379)),
                password=os.getenv("REDIS_PASSWORD", "12345678"),
                db=0,
            )
            if await self.r.ping():
                logger.info("redis 连接成功")

    async def bind(self):
        while True:
            try:
                url = "http://www.zdopen.com/ShortProxy/BindIP?api=202406041824314753&akey=4fee8e19764876e1&i=2"
                resp: Response = await self.s.get(url)
                logger.debug(resp.json())
                await asyncio.sleep(10)
            except Exception as e:
                logger.warning(f"绑定失败: {e}")

    async def cache_ips(self):
        while True:
            try:
                url = "https://20tools.net/api/proxies/all?sign=ftd*kcm.ygh4mjp7ERJ"
                resp: Response = await self.s.get(url)
                ips = resp.json()
                if not ips:
                    continue
                await self.r.sadd("walmart_ips", *ips)
                await self.r.expire("walmart_ips", 1)
                logger.debug(f"缓存ip ({len(ips)}): {ips}")
                await asyncio.sleep(1)
            except Exception as e:
                logger.warning(f"缓存ip失败: {e}")

    async def close(self):
        await self.r.aclose()
        await self.s.close()
        logger.info("资源已回收")

    async def run_during_night(self):
        """在晚上运行任务"""
        while True:
            now = datetime.now().time()
            if time(22, 0) > now and now > time(7, 0):
                for task in self._tasks:
                    if task and not task.done():
                        task.cancel()
                logger.info("不在指定时间范围内, 停止运行")
                break
            await asyncio.sleep(60)

    async def run(self, monitor: bool = False):
        try:
            await self.connect()
            self._tasks = [
                asyncio.create_task(self.bind()),
                asyncio.create_task(self.cache_ips()),
            ]
            if monitor:
                monitor_task = asyncio.create_task(self.run_during_night())
                await asyncio.gather(*self._tasks, monitor_task)
            else:
                await asyncio.gather(*self._tasks)
        except asyncio.CancelledError:
            logger.info("任务已取消")
            # raise
        finally:
            await self.close()


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    if IS_DEBUG:
        loop.run_until_complete(Subsidiary().run())
    else:
        loop.run_until_complete(Subsidiary().run(monitor=True))
