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

# ==========================================
# 接口配置
# ==========================================
SESSION_DIR = r'./session'       # 监控的工作区目录
CHECK_INTERVAL = 5               # 检查频率
BILIUP_PATH = "./biliup"           # biliup 命令
CONFIG_FILE = "upload_config.json"  # 配置文件路径
DONE_FLAG = "split_done.flag"    # monitorSongs.py 生成的标记
UPLOAD_FLAG = "upload_done.flag" # 本脚本生成的完成标记

# 初始化日志
logger = get_system_logger('upload')
# ==========================================

class UploadConfig:
    """上传配置管理器"""
    def __init__(self, config_path):
        self.config_path = Path(config_path)
        self.config = self.load_config()
        
    def load_config(self):
        """加载配置文件"""
        try:
            if not self.config_path.exists():
                logger.error(f"配置文件不存在: {self.config_path}")
                return self.get_default_config()
            
            with open(self.config_path, 'r', encoding='utf-8') as f:
                config = json.load(f)
                logger.info(f"成功加载配置文件: {self.config_path}")
                return config
        except Exception as e:
            log_exception(logger, e, "加载配置文件失败")
            return self.get_default_config()
    
    def get_default_config(self):
        """默认配置"""
        logger.warning("使用默认配置")
        return {
            "upload_settings": {
                "tid": 31,
                "copyright": 2,
                "source": "直播回放",
                "cover": ""
            },
            "template": {
                "title": "{streamer}_{date}",
                "description": "自动录制剪辑\n\n{songs_list}",
                "tag": "翻唱,直播切片,唱歌,音乐",
                "dynamic": ""
            },
            "streamers": {},
            "quotes": [],
            "filename_patterns": {
                "patterns": []
            }
        }
    
    def parse_filename(self, filename):
        """从文件名解析主播名和日期"""
        patterns = self.config.get("filename_patterns", {}).get("patterns", [])
        
        for pattern_config in patterns:
            regex = pattern_config.get("regex")
            if not regex:
                continue
                
            match = re.match(regex, filename)
            if match:
                data = match.groupdict()
                date_format = pattern_config.get("date_format", "{date}")
                
                # 格式化日期
                try:
                    formatted_date = date_format.format(**data)
                    data['date'] = formatted_date
                except KeyError:
                    pass
                
                logger.debug(f"文件名匹配成功: {pattern_config.get('name')} -> {data}")
                return data
        
        # 默认返回原始文件名
        logger.warning(f"文件名未匹配任何模式: {filename}")
        return {"streamer": filename, "date": ""}
    
    def get_random_quote(self):
        """随机获取一句名言"""
        quotes = self.config.get("quotes", [])
        if not quotes:
            return {"text": "", "author": ""}
        return random.choice(quotes)

class UploadHandler(FileSystemEventHandler):
    def __init__(self, config):
        self.processing_sets = set()
        self.config = config

    def on_created(self, event):
        # 监听 split_done.flag 文件的生成
        if not event.is_directory and event.src_path.lower().endswith(DONE_FLAG):
            logger.debug(f"检测到切割完成标记: {event.src_path}")
            self.handle_upload(Path(event.src_path))

    def on_moved(self, event):
        if not event.is_directory and event.dest_path.lower().endswith(DONE_FLAG):
            logger.debug(f"检测到切割完成标记移动: {event.dest_path}")
            self.handle_upload(Path(event.dest_path))

    def handle_upload(self, flag_path):
        work_dir = flag_path.parent
        video_stem = work_dir.name
        upload_done = work_dir / UPLOAD_FLAG
        split_dir = work_dir / "split_video"

        # 防重复检查
        if upload_done.exists() or video_stem in self.processing_sets:
            logger.debug(f"上传已完成或正在处理，跳过: {video_stem}")
            return

        logger.info("="*50)
        logger.info(f"准备上传: {video_stem}")
        logger.info("="*50)
        self.processing_sets.add(video_stem)

        try:
            # 1. 解析文件名
            parsed = self.config.parse_filename(video_stem)
            streamer = parsed.get('streamer', video_stem)
            date = parsed.get('date', '')
            
            logger.info(f"主播: {streamer}, 日期: {date}")
            
            # 2. 读取歌曲信息
            songs_json = work_dir / "songs.json"
            songs_txt = work_dir / "songs.txt"
            songs = []
            song_count = 0
            songs_list = ""
            
            if songs_json.exists():
                try:
                    with open(songs_json, 'r', encoding='utf-8') as f:
                        data = json.load(f)
                        songs = data.get('songs', [])
                        song_count = len(songs)
                    logger.info(f"读取到 {song_count} 首歌曲")
                except Exception as e:
                    log_exception(logger, e, "读取 songs.json 失败")
            
            if songs_txt.exists():
                songs_list = songs_txt.read_text(encoding='utf-8').strip()
                logger.info("已读取歌单文本")
            
            # 3. 获取随机名言
            quote = self.config.get_random_quote()
            daily_quote = quote.get('text', '')
            quote_author = quote.get('author', '')
            
            # 4. 构建模板变量
            template_vars = {
                'streamer': streamer,
                'date': date,
                'song_count': song_count,
                'songs_list': songs_list,
                'daily_quote': daily_quote,
                'quote_author': quote_author
            }
            
            # 5. 渲染标题和简介
            template = self.config.config.get('template', {})
            title = template.get('title', '{streamer}_{date}').format(**template_vars)
            description = template.get('description', '{songs_list}').format(**template_vars)
            dynamic = template.get('dynamic', '').format(**template_vars)
            
            # 6. 获取标签（优先使用主播专属标签）
            streamers_config = self.config.config.get('streamers', {})
            if streamer in streamers_config:
                tags = streamers_config[streamer].get('tags', template.get('tag', ''))
                logger.info(f"使用主播专属标签: {streamer}")
            else:
                tags = template.get('tag', '翻唱,唱歌,音乐').format(**template_vars)
            
            logger.info(f"标题: {title}")
            logger.info(f"标签: {tags}")
            logger.debug(f"简介预览: {description[:100]}...")
            
            # 7. 获取所有切片视频
            video_files = sorted([str(v) for v in split_dir.glob("*") if v.suffix.lower() in {'.mp4', '.mkv', '.mov', '.flv'}])
            
            if not video_files:
                logger.error(f"切片目录 {split_dir} 内没找到视频")
                return
            
            logger.info(f"找到 {len(video_files)} 个视频分片")

            # 8. 读取上传设置
            upload_settings = self.config.config.get('upload_settings', {})
            tid = upload_settings.get('tid', 31)
            copyright_val = upload_settings.get('copyright', 2)
            source = upload_settings.get('source', '直播回放')
            cover = upload_settings.get('cover', '')

            # 8. 刷新 biliup 登录信息
            renew_cmd = [BILIUP_PATH, "renew"]
            logger.info("尝试刷新 biliup 登录信息")
            renew_result = subprocess.run(renew_cmd, shell=False, capture_output=True, text=True, encoding='utf-8')
            if renew_result.returncode != 0:
                logger.warning(f"biliup renew 返回非 0: {renew_result.returncode}")
                logger.debug(f"renew stderr: {renew_result.stderr.strip()}")
            else:
                logger.info("biliup renew 成功")

            # 9. 执行上传
            logger.info(f"启动 biliup 投稿...")
            cmd = [
                BILIUP_PATH, "upload",
                *video_files,
                "--title", title,
                "--tid", str(tid),
                "--tag", tags,
                "--copyright", str(copyright_val),
                "--source", source,
                "--desc", description
            ]
            
            if dynamic:
                cmd.extend(["--dynamic", dynamic])
            
            if cover and Path(cover).exists():
                cmd.extend(["--cover", cover])
            
            logger.debug(f"biliup 命令: {' '.join(cmd[:5])}... (共 {len(video_files)} 个文件)")

            # shell=True 确保在 Windows 下调用正常
            result = subprocess.run(cmd, shell=False, capture_output=True, text=True, encoding='utf-8')

            if result.returncode == 0:
                logger.info(f"投稿成功: {video_stem}")
                logger.info(f"标题: {title}")
                upload_done.touch() # 盖上"上传完成"戳
                logger.info("生成上传完成标记")

                # 上传成功后清理空间
                try:
                    # 1. 删除 split_video 目录
                    if split_dir.exists():
                        shutil.rmtree(split_dir)
                        logger.info(f"已删除切片目录: {split_dir}")
                    
                    # 2. 删除原视频文件 (匹配常见视频后缀)
                    for ext in ['.mp4', '.mkv', '.mov', '.flv', '.ts']:
                        original_video = work_dir / f"{video_stem}{ext}"
                        if original_video.exists():
                            original_video.unlink()
                            logger.info(f"已删除原视频: {original_video}")
                except Exception as cleanup_err:
                    logger.error(f"清理空间失败: {cleanup_err}")
            else:
                logger.error(f"投稿失败，错误码: {result.returncode}")
                logger.error(f"错误信息: {result.stderr[:500]}")

        except Exception as e:
            log_exception(logger, e, "上传处理异常")
        finally:
            self.processing_sets.discard(video_stem)
            logger.info("="*50)

def main():
    path = Path(SESSION_DIR)
    path.mkdir(parents=True, exist_ok=True)

    logger.info("="*50)
    logger.info("上传模块启动 (Biliup 自动投稿)")
    logger.info("="*50)
    logger.info(f"监控目录: {SESSION_DIR}")
    logger.info(f"Biliup 路径: {BILIUP_PATH}")
    logger.info(f"配置文件: {CONFIG_FILE}")
    
    # 加载配置
    config = UploadConfig(CONFIG_FILE)

    event_handler = UploadHandler(config)
    observer = Observer()
    observer.schedule(event_handler, str(path), recursive=True)
    
    # 启动时扫描已有目录：如果有 split_done.flag 但没 upload_done.flag，补投
    logger.info("扫描待上传任务...")
    scan_count = 0
    for sub_dir in path.iterdir():
        if sub_dir.is_dir():
            split_flag = sub_dir / DONE_FLAG
            upload_flag = sub_dir / UPLOAD_FLAG
            if split_flag.exists() and not upload_flag.exists():
                logger.info(f"发现待上传任务: {sub_dir.name}")
                event_handler.handle_upload(split_flag)
                scan_count += 1
    logger.info(f"扫描完成，处理 {scan_count} 个待上传任务")

    observer.start()
    logger.info("文件监控已启动")
    
    try:
        while True:
            time.sleep(CHECK_INTERVAL)
    except KeyboardInterrupt:
        logger.info("接收到停止信号，正在关闭...")
        observer.stop()
    observer.join()
    logger.info("上传模块已停止")

if __name__ == "__main__":
    main()
