import yt_dlp
import os
from typing import List, Dict, Optional, Tuple
from loguru import logger
from uuid import uuid4

from app.utils import utils
from app.services import video as VideoService


class YoutubeService:
    def __init__(self):
        self.supported_formats = ['mp4', 'mkv', 'webm', 'flv', 'avi']

    def _get_video_formats(self, url: str) -> List[Dict]:
        """获取视频可用的格式列表"""
        ydl_opts = {
            'quiet': True,
            'no_warnings': True
        }

        try:
            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                info = ydl.extract_info(url, download=False)
                formats = info.get('formats', [])

                format_list = []
                for f in formats:
                    format_info = {
                        'format_id': f.get('format_id', 'N/A'),
                        'ext': f.get('ext', 'N/A'),
                        'resolution': f.get('format_note', 'N/A'),
                        'filesize': f.get('filesize', 'N/A'),
                        'vcodec': f.get('vcodec', 'N/A'),
                        'acodec': f.get('acodec', 'N/A')
                    }
                    format_list.append(format_info)

                return format_list
        except Exception as e:
            logger.error(f"获取视频格式失败: {str(e)}")
            raise

    def _validate_format(self, output_format: str) -> None:
        """验证输出格式是否支持"""
        if output_format.lower() not in self.supported_formats:
            raise ValueError(
                f"不支持的视频格式: {output_format}。"
                f"支持的格式: {', '.join(self.supported_formats)}"
            )

    async def download_video(
            self,
            url: str,
            resolution: str,
            output_format: str = 'mp4',
            rename: Optional[str] = None
    ) -> Tuple[str, str, str]:
        """
        下载指定分辨率的视频
        
        Args:
            url: YouTube视频URL
            resolution: 目标分辨率 ('2160p', '1440p', '1080p', '720p' etc.)
                       注意：对于类似'1080p60'的输入会被处理为'1080p'
            output_format: 输出视频格式
            rename: 可选的重命名
            
        Returns:
            Tuple[str, str, str]: (task_id, output_path, filename)
        """
        try:
            task_id = str(uuid4())
            self._validate_format(output_format)

            # 标准化分辨率格式
            base_resolution = resolution.split('p')[0] + 'p'
            
            # 获取所有可用格式
            formats = self._get_video_formats(url)

            # 查找指定分辨率的最佳视频格式
            target_format = None
            for fmt in formats:
                fmt_resolution = fmt['resolution']
                # 将格式的分辨率也标准化后进行比较
                if fmt_resolution != 'N/A':
                    fmt_base_resolution = fmt_resolution.split('p')[0] + 'p'
                    if fmt_base_resolution == base_resolution and fmt['vcodec'] != 'none':
                        target_format = fmt
                        break

            if target_format is None:
                # 收集可用分辨率时也进行标准化
                available_resolutions = set(
                    fmt['resolution'].split('p')[0] + 'p'
                    for fmt in formats
                    if fmt['resolution'] != 'N/A' and fmt['vcodec'] != 'none'
                )
                raise ValueError(
                    f"未找到 {base_resolution} 分辨率的视频。"
                    f"可用分辨率: {', '.join(sorted(available_resolutions))}"
                )

            # 创建输出目录
            output_dir = utils.video_dir()
            os.makedirs(output_dir, exist_ok=True)

            # 设置下载选项
            if rename:
                # 如果指定了重命名，直接使用新名字
                filename = f"{rename}.{output_format}"
                output_template = os.path.join(output_dir, filename)
            else:
                # 否则使用任务ID和原标题
                output_template = os.path.join(output_dir, f'{task_id}_%(title)s.%(ext)s')

            ydl_opts = {
                'format': f"{target_format['format_id']}+bestaudio[ext=m4a]/best",
                'outtmpl': output_template,
                'merge_output_format': output_format.lower(),
                'postprocessors': [{
                    'key': 'FFmpegVideoConvertor',
                    'preferedformat': output_format.lower(),
                }]
            }

            # 执行下载
            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                info = ydl.extract_info(url, download=True)
                if rename:
                    # 如果指定了重命名，使用新文件名
                    output_path = output_template
                    filename = os.path.basename(output_path)
                else:
                    # 否则使用原始标题
                    video_title = info.get('title', task_id)
                    filename = f"{task_id}_{video_title}.{output_format}"
                    output_path = os.path.join(output_dir, filename)

            logger.info(f"视频下载成功: {output_path}")
            return task_id, output_path, filename

        except Exception as e:
            logger.exception("下载视频失败")
            raise
