import json
import time
import requests
import re
import shutil
import subprocess
import random
from pathlib import Path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from logger import get_system_logger, log_exception

# ================= 配置区域 =================
SESSION_DIR = Path("./session")
COOKIE_FILE = Path("./cookies.json")
CHECK_INTERVAL = 5

# 合集 ID 配置
SEASON_ID_A = 7196643   # 合集 A (同名视频)
SEASON_ID_B = 7196624   # 合集 B (Upload切片)

# 自动寻找 biliup
BILIUP_PATH = shutil.which("biliup") or "biliup"
# 初始化日志
logger = get_system_logger("add_to_collection.py")
# ===========================================

class BiliCollectionClient:
    def __init__(self):
        self.load_cookies()
        self.session = requests.Session()
        self.session.headers.update({
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
            "Referer": "https://member.bilibili.com/platform/upload-manager/distribution"
        })

    def load_cookies(self):
        if not COOKIE_FILE.exists():
            raise FileNotFoundError(f"Cookies 文件不存在: {COOKIE_FILE}")
        with open(COOKIE_FILE, "r", encoding="utf-8") as f:
            data = json.load(f)
        self.cookies = {c["name"]: c["value"] for c in data.get("cookie_info", {}).get("cookies", [])} if "cookie_info" in data else data
        self.csrf = self.cookies.get("bili_jct")

    def get_video_info(self, bvid):
        url = "https://api.bilibili.com/x/web-interface/view"
        try:
            self.session.cookies.update(self.cookies)
            res = self.session.get(url, params={"bvid": bvid}, timeout=10).json()
            if res["code"] == 0:
                d = res["data"]
                return {"aid": d["aid"], "cid": d["cid"], "title": d["title"], "charging_pay": 0}
        except Exception as e:
            logger.error(f"获取视频信息失败: {e}")
        return None

    def resolve_section_id(self, sid):
        url = "https://member.bilibili.com/x2/creative/web/seasons"
        try:
            self.session.cookies.update(self.cookies)
            res = self.session.get(url, params={"pn": 1, "ps": 50}).json()
            for s in res.get("data", {}).get("seasons", []):
                if s.get("season", {}).get("id") == sid:
                    return s.get("sections", {}).get("sections", [])[0]["id"]
        except: pass
        return None

    def add_videos_batch(self, section_id, episodes):
        if not episodes: return True
        # 频率控制
        wait = random.uniform(5.0, 10.0)
        logger.info(f"☕ 模拟人工操作，等待 {wait:.2f}s 后提交到合集...")
        time.sleep(wait)

        url = "https://member.bilibili.com/x2/creative/web/season/section/episodes/add"
        params = {"csrf": self.csrf}
        try:
            res = self.session.post(url, params=params, json={"sectionId": section_id, "episodes": episodes}).json()
            return res["code"] == 0
        except Exception as e:
            log_exception(logger, e, "批量添加合集异常")
            return False

class CollectionHandler(FileSystemEventHandler):
    def __init__(self, client, sid_a, sid_b):
        self.client = client
        self.sid_a = sid_a
        self.sid_b = sid_b
        self.ansi_escape = re.compile(r"\x1b\[[0-9;]*[A-Za-z]")

    def on_created(self, event):
        # 监听文件夹创建或 bvid.txt 创建
        if event.is_directory or event.src_path.endswith("bvid.txt"):
            self.process_all()

    def process_all(self):
        recent = self.fetch_biliup_list()
        pending_a, pending_b = [], []

        for folder in SESSION_DIR.iterdir():
            if not folder.is_dir(): continue
            
            # 任务 A: 同名视频 -> 合集 A
            flag_a = folder / "collection_a_done.flag"
            if self.sid_a and not flag_a.exists():
                bvid = self.match_bvid(folder.name, recent)
                if bvid:
                    info = self.client.get_video_info(bvid)
                    if info: pending_a.append((folder, info))

            # 任务 B: 切片视频 -> 合集 B
            flag_b = folder / "collection_b_done.flag"
            txt = folder / "bvid.txt"
            if self.sid_b and not flag_b.exists() and txt.exists():
                try:
                    bvid = txt.read_text(encoding='utf-8').strip()
                    if bvid.startswith("BV"):
                        info = self.client.get_video_info(bvid)
                        if info: pending_b.append((folder, info))
                except: pass

        # 批量执行提交
        if pending_a:
            if self.client.add_videos_batch(self.sid_a, [i[1] for i in pending_a]):
                for f, _ in pending_a: (f / "collection_a_done.flag").touch()
                logger.info(f"合集 A 更新完成: {len(pending_a)}个任务")

        if pending_b:
            if self.client.add_videos_batch(self.sid_b, [i[1] for i in pending_b]):
                for f, _ in pending_b: (f / "collection_b_done.flag").touch()
                logger.info(f"合集 B 更新完成: {len(pending_b)}个任务")

    def fetch_biliup_list(self):
        try:
            res = subprocess.run([BILIUP_PATH, "list"], capture_output=True, text=True, encoding='utf-8')
            clean_out = self.ansi_escape.sub("", res.stdout)
            return [{"bvid": l.split()[0], "title": "".join(l.split()[1:])} for l in clean_out.splitlines() if l.startswith("BV")]
        except: return []

    def match_bvid(self, name, vlist):
        n = lambda x: re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9]', '', x).lower()
        target = n(name)
        for v in vlist:
            vn = n(v['title'])
            if target in vn or vn in target: return v['bvid']
        return None

def main():
    logger.info("="*50)
    logger.info("合集监控模块启动")
    logger.info("="*50)

    client = BiliCollectionClient()
    sid_a = client.resolve_section_id(SEASON_ID_A) if SEASON_ID_A > 0 else None
    sid_b = client.resolve_section_id(SEASON_ID_B) if SEASON_ID_B > 0 else None

    handler = CollectionHandler(client, sid_a, sid_b)
    handler.process_all() # 初始扫描

    observer = Observer()
    observer.schedule(handler, str(SESSION_DIR), recursive=False)
    observer.start()
    
    try:
        while True:
            time.sleep(CHECK_INTERVAL)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

if __name__ == "__main__":
    main()