"""
命令行界面
"""
import click
from pathlib import Path
from .auth import BilibiliAuth
from .parser import BilibiliParser
from .downloader import BilibiliDownloader
from .transcriber import BilibiliTranscriber
from .pdf_converter import PDFConverter


@click.group()
@click.version_option(version='1.2.2')
def cli():
    """B站视频下载工具 - 支持扫码登录和高清下载
    
    \b
    使用示例:
      bili-dl login                          # 扫码登录
      bili-dl download BV1ms4y1Y76i          # 下载视频
      bili-dl download BV1xx --quality 4k    # 指定清晰度
      bili-dl status                         # 查看登录状态
      bili-dl logout                         # 退出登录
    
    \b
    ⚠️  免责声明:
      本工具仅供个人学习研究使用，请勿用于商业用途。
      下载的视频内容版权归原作者所有，请尊重创作者权益。
      使用本工具即表示您同意遵守相关法律法规和平台规则。
    """
    pass


@cli.command()
def login():
    """扫码登录B站账号
    
    登录后可以:
    - 下载大会员专属清晰度(1080P+/4K)
    - 下载需要登录才能观看的视频
    - 避免游客限制
    """
    auth = BilibiliAuth()
    auth.login()


@cli.command()
def logout():
    """退出登录,清除本地保存的登录信息"""
    auth = BilibiliAuth()
    auth.clear_credentials()


@cli.command()
def status():
    """查看当前登录状态和会员信息"""
    auth = BilibiliAuth()
    credentials = auth.load_credentials()
    
    if credentials:
        user_info = credentials['user_info']
        auth.display_user_info(user_info)
    else:
        print("❌ 未登录")
        print("\n使用 'bili-dl login' 命令登录")


@cli.command()
@click.argument('url_or_bvid')
@click.option(
    '--quality', '-q',
    type=click.Choice(['360p', '480p', '720p', '1080p', '1080p+', '1080p60', '4k'], case_sensitive=False),
    default='1080p',
    help='视频清晰度 (默认: 1080p)'
)
@click.option(
    '--output', '-o',
    type=click.Path(),
    default='downloads',
    help='输出目录 (默认: downloads)'
)
@click.option(
    '--page', '-p',
    type=int,
    default=None,
    help='指定下载的分P编号 (默认: 自动从URL提取或下载第1P)'
)
@click.option(
    '--with-cover',
    is_flag=True,
    help='同时下载视频封面'
)
def download(url_or_bvid, quality, output, page, with_cover):
    """下载B站视频
    
    \b
    参数:
      URL_OR_BVID  视频链接或BV号
    
    \b
    示例:
      bili-dl download BV1ms4y1Y76i
      bili-dl download https://www.bilibili.com/video/BV1ms4y1Y76i
      bili-dl download BV1ms4y1Y76i --quality 4k
      bili-dl download BV1ms4y1Y76i --page 2
      bili-dl download "https://www.bilibili.com/video/BV1xx?p=3"
      bili-dl download BV1ms4y1Y76i -o /path/to/save
    """
    # 清晰度映射
    quality_map = {
        '360p': 16,
        '480p': 32,
        '720p': 64,
        '1080p': 80,
        '1080p+': 112,
        '1080p60': 116,
        '4k': 120,
    }
    
    quality_id = quality_map.get(quality.lower(), 80)
    
    # 加载登录信息
    auth = BilibiliAuth()
    credentials = auth.load_credentials()
    
    cookies = None
    if credentials:
        cookies = credentials['cookies']
        print(f"✅ 使用登录状态下载 ({credentials['user_info']['username']})")
    else:
        print("ℹ️  未登录,使用游客权限下载")
        if quality_id >= 112:
            print("⚠️  高清晰度可能需要登录,建议先执行 'bili-dl login'")
    
    try:
        # 解析视频信息
        parser = BilibiliParser(cookies)
        bvid, url_page = parser.extract_bvid(url_or_bvid)
        
        # 确定最终的分P编号：命令行参数优先于URL参数
        page_number = page if page is not None else url_page
        
        print(f"\n正在获取视频信息: {bvid}")
        video_info = parser.get_video_info(bvid)
        
        print(f"\n视频标题: {video_info['title']}")
        print(f"UP主: {video_info['owner']['name']}")
        print(f"时长: {video_info['duration']}秒")
        
        # 处理分P逻辑
        pages = video_info['pages']
        if len(pages) > 1:
            print(f"分P数量: {len(pages)}")
            
            # 验证分P编号是否有效
            if page_number > len(pages):
                print(f"⚠️  视频只有 {len(pages)} 个分P，将下载第1P")
                page_number = 1
            elif page_number < 1:
                print(f"⚠️  分P编号无效，将下载第1P")
                page_number = 1
            
            # 获取当前分P信息
            current_page = pages[page_number - 1]
            cid = current_page['cid']
            page_title = current_page.get('part', f'P{page_number}')
            print(f"下载分P: P{page_number}/{len(pages)} - {page_title}")
        else:
            # 单P视频
            cid = video_info['cid']
            if page_number > 1:
                print(f"⚠️  这是单P视频，将下载唯一的分P")
        
        # 检查可用清晰度
        print(f"\n正在检查可用清晰度...")
        available_qualities = parser.get_available_qualities(bvid, cid)
        print(f"可用清晰度: {', '.join([q['name'] for q in available_qualities])}")
        
        # 获取视频流
        print(f"\n正在获取视频流...")
        stream_info = parser.get_video_stream(bvid, cid, quality_id)
        selected_stream = parser.select_stream(stream_info, quality_id)
        
        if selected_stream['quality_name'] != parser.QUALITY_MAP.get(quality_id):
            print(f"⚠️  目标清晰度不可用,将下载: {selected_stream['quality_name']}")
        
        # 下载视频
        downloader = BilibiliDownloader(output, cookies)
        success = downloader.download_video(
            video_url=selected_stream['video_url'],
            audio_url=selected_stream['audio_url'],
            title=video_info['title'],
            bvid=bvid,
            quality_name=selected_stream['quality_name'],
            merge_needed=selected_stream['merge_needed']
        )
        
        # 下载封面
        if success and with_cover:
            print("\n正在下载封面...")
            downloader.download_cover(video_info['pic'], bvid, video_info['title'])
        
        if success:
            print("\n🎉 任务完成!")
        else:
            print("\n❌ 下载失败")
            exit(1)
            
    except ValueError as e:
        print(f"\n❌ 输入错误: {e}")
        exit(1)
    except Exception as e:
        print(f"\n❌ 发生错误: {e}")
        exit(1)


@cli.command()
@click.argument('url_or_bvid')
def info(url_or_bvid):
    """查看视频详细信息(不下载)
    
    \b
    示例:
      bili-dl info BV1ms4y1Y76i
    """
    # 加载登录信息
    auth = BilibiliAuth()
    credentials = auth.load_credentials()
    cookies = credentials['cookies'] if credentials else None
    
    try:
        parser = BilibiliParser(cookies)
        bvid, url_page = parser.extract_bvid(url_or_bvid)
        
        print(f"\n正在获取视频信息: {bvid}")
        if url_page > 1:
            print(f"(URL中指定的分P: P{url_page})")
        
        video_info = parser.get_video_info(bvid)
        
        print("\n" + "="*60)
        print("视频信息")
        print("="*60)
        print(f"标题: {video_info['title']}")
        print(f"BV号: {video_info['bvid']}")
        print(f"AV号: {video_info['aid']}")
        print(f"UP主: {video_info['owner']['name']} (UID: {video_info['owner']['mid']})")
        print(f"时长: {video_info['duration']}秒")
        print(f"简介: {video_info['desc'][:100]}{'...' if len(video_info['desc']) > 100 else ''}")
        
        # 分P信息
        if len(video_info['pages']) > 1:
            print(f"\n分P数量: {len(video_info['pages'])}")
            print("分P列表:")
            for i, page in enumerate(video_info['pages'], 1):
                duration_min = page['duration'] // 60
                duration_sec = page['duration'] % 60
                print(f"  P{i}: {page['part']} (时长: {duration_min}:{duration_sec:02d}, cid: {page['cid']})")
        else:
            print(f"\n单P视频 (cid: {video_info['cid']})")
        
        # 可用清晰度
        print(f"\n正在检查可用清晰度...")
        available_qualities = parser.get_available_qualities(bvid, video_info['cid'])
        print("可用清晰度:")
        for q in available_qualities:
            print(f"  - {q['name']} (ID: {q['id']})")
        
        print("="*60 + "\n")
        
    except Exception as e:
        print(f"\n❌ 发生错误: {e}")
        exit(1)


@cli.command()
@click.argument('video_path', type=click.Path(exists=True))
@click.option(
    '--model', '-m', 
    default='base',
    type=click.Choice(['tiny', 'base', 'small', 'medium', 'large'], case_sensitive=False),
    help='Whisper模型 (默认: base)'
)
@click.option(
    '--language', '-l',
    default='zh',
    help='语言代码 (默认: zh中文)'
)
@click.option(
    '--output', '-o',
    type=click.Path(),
    help='输出文件路径'
)
@click.option(
    '--srt',
    is_flag=True,
    help='生成SRT字幕文件'
)
@click.option(
    '--timestamps',
    is_flag=True,
    help='在文本中显示时间戳'
)
def transcribe(video_path, model, language, output, srt, timestamps):
    """转录视频为文本
    
    使用 OpenAI Whisper 模型对视频进行语音识别
    
    \b
    示例:
      bili-dl transcribe video.mp4
      bili-dl transcribe video.mp4 --srt
      bili-dl transcribe video.mp4 --model medium --language zh
      bili-dl transcribe video.mp4 -m small -o output.txt
    
    \b
    模型选择:
      tiny   - 最快,准确度较低 (适合快速预览)
      base   - 快,准确度中等 (默认,日常使用)
      small  - 中等速度和准确度 (推荐中文)
      medium - 慢,准确度好 (高质量需求)
      large  - 最慢,准确度最好 (专业级)
    """
    try:
        video_path = Path(video_path)
        print(f"\n正在转录: {video_path.name}")
        print(f"模型: {model}, 语言: {language}")
        print("-" * 50)
        
        transcriber = BilibiliTranscriber(model_name=model, language=language)
        
        if srt:
            # 生成SRT字幕
            srt_path = transcriber.transcribe_to_srt(
                video_path,
                output_path=Path(output) if output else None
            )
            print(f"\n🎉 转录完成!")
            print(f"SRT字幕: {srt_path}")
        else:
            # 只生成文本
            result = transcriber.transcribe_video(
                video_path,
                output_path=Path(output) if output else None,
                verbose=True
            )
            print(f"\n🎉 转录完成!")
            print(f"文本长度: {len(result['text'])} 字符")
        
    except Exception as e:
        print(f"\n❌ 转录失败: {e}")
        exit(1)


@cli.command()
@click.argument('video_dir', type=click.Path(exists=True, file_okay=False, dir_okay=True))
@click.option(
    '--model', '-m',
    default='base',
    type=click.Choice(['tiny', 'base', 'small', 'medium', 'large'], case_sensitive=False),
    help='Whisper模型 (默认: base)'
)
@click.option(
    '--language', '-l',
    default='zh',
    help='语言代码 (默认: zh中文)'
)
@click.option(
    '--output-dir',
    type=click.Path(),
    help='输出目录 (默认: 各视频同目录)'
)
@click.option(
    '--recursive', '-r',
    is_flag=True,
    help='递归处理子目录'
)
def batch_transcribe(video_dir, model, language, output_dir, recursive):
    """批量转录目录下的所有视频
    
    扫描目录中的所有MP4视频文件并进行转录
    
    \b
    示例:
      bili-dl batch-transcribe ./downloads/
      bili-dl batch-transcribe ./downloads/ --recursive
      bili-dl batch-transcribe ./downloads/ --model small
      bili-dl batch-transcribe ./downloads/ -m medium -r
    
    \b
    注意:
      - 会自动跳过已转录的文件(已有.srt或_transcript.txt)
      - 单个文件失败不影响其他文件处理
      - 使用 -r 选项可递归处理子目录
    """
    try:
        video_dir = Path(video_dir)
        output_dir = Path(output_dir) if output_dir else None
        
        print(f"\n开始批量转录")
        print(f"目录: {video_dir}")
        print(f"模型: {model}, 语言: {language}")
        print(f"递归: {'是' if recursive else '否'}")
        print("=" * 50)
        
        transcriber = BilibiliTranscriber(model_name=model, language=language)
        
        result = transcriber.batch_transcribe(
            video_dir=video_dir,
            output_dir=output_dir,
            recursive=recursive,
            generate_srt=True
        )
        
        print("\n" + "=" * 50)
        print(f"🎉 批量转录完成!")
        print(f"总文件数: {result['total']}")
        print(f"成功: {result['success']}")
        print(f"失败: {result['failed']}")
        
        if result['failed'] > 0 and result.get('failed_files'):
            print("\n失败文件:")
            for file in result['failed_files']:
                print(f"  - {file}")
        
    except Exception as e:
        print(f"\n❌ 批量转录失败: {e}")
        exit(1)


@cli.command(name='export-pdf')
@click.argument('markdown_file', type=click.Path(exists=True))
@click.option(
    '--output', '-o',
    type=click.Path(),
    help='输出PDF路径 (默认: 同名.pdf)'
)
@click.option(
    '--style',
    type=click.Path(exists=True),
    help='自定义CSS样式文件'
)
def export_pdf(markdown_file, output, style):
    """将Markdown文件转换为PDF
    
    自动化转换,支持中文字体和图片嵌入
    
    \b
    示例:
      bili-dl export-pdf report.md
      bili-dl export-pdf notes.md -o output.pdf
      bili-dl export-pdf document.md --style custom.css
    
    \b
    功能特性:
      - 自动嵌入图片 (支持相对路径)
      - 中文字体支持
      - 精美排版样式
      - 支持代码高亮
    """
    try:
        markdown_file = Path(markdown_file)
        
        # 加载自定义样式
        custom_css = None
        if style:
            with open(style, 'r', encoding='utf-8') as f:
                custom_css = f.read()
            print(f"✅ 已加载自定义样式: {style}\n")
        
        # 创建转换器
        converter = PDFConverter(custom_css=custom_css)
        
        # 转换
        pdf_path = converter.convert_markdown_to_pdf(
            str(markdown_file),
            output_path=output,
            verbose=True
        )
        
        print(f"\n🎉 转换完成!")
        print(f"PDF路径: {pdf_path}")
        
    except Exception as e:
        print(f"\n❌ 转换失败: {e}")
        import traceback
        traceback.print_exc()
        exit(1)


@cli.command(name='batch-export-pdf')
@click.argument('directory', type=click.Path(exists=True, file_okay=False))
@click.option(
    '--recursive', '-r',
    is_flag=True,
    help='递归处理子目录'
)
@click.option(
    '--output', '-o',
    type=click.Path(),
    help='输出目录 (默认: 原地生成)'
)
@click.option(
    '--style',
    type=click.Path(exists=True),
    help='自定义CSS样式文件'
)
def batch_export_pdf(directory, recursive, output, style):
    """批量转换目录下所有Markdown文件为PDF
    
    扫描目录中的所有.md文件并转换为PDF
    
    \b
    示例:
      bili-dl batch-export-pdf ./reports/
      bili-dl batch-export-pdf ./notes/ --recursive
      bili-dl batch-export-pdf ./docs/ -r -o ./pdf_output/
      bili-dl batch-export-pdf ./content/ --style custom.css
    
    \b
    注意:
      - 自动跳过转换失败的文件
      - 使用 -r 递归处理子目录
      - 相对路径的图片会自动处理
    """
    try:
        directory = Path(directory)
        
        # 加载自定义样式
        custom_css = None
        if style:
            with open(style, 'r', encoding='utf-8') as f:
                custom_css = f.read()
            print(f"✅ 已加载自定义样式: {style}\n")
        
        # 创建转换器
        converter = PDFConverter(custom_css=custom_css)
        
        # 批量转换
        pdf_files = converter.batch_convert(
            str(directory),
            recursive=recursive,
            output_dir=output,
            verbose=True
        )
        
        print(f"\n🎉 批量转换完成!")
        print(f"成功生成 {len(pdf_files)} 个PDF文件")
        
    except Exception as e:
        print(f"\n❌ 批量转换失败: {e}")
        import traceback
        traceback.print_exc()
        exit(1)


def main():
    """主入口"""
    cli()


if __name__ == '__main__':
    main()
