#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""端到端流程验证：模拟真实用户从空库到数据迁移的完整链路。"""
import os
import shutil
import sys
import tempfile
from pathlib import Path

_ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(_ROOT))
os.environ["QT_QPA_PLATFORM"] = "offscreen"

from PIL import Image
from comic_asset_manager.db import Database
from comic_asset_manager.library import (
    export_library, import_file, import_folder, import_library, scan_files,
)
from comic_asset_manager.models import AssetType, Chapter, Series
from comic_asset_manager import thumbnail

PASS = "\033[32m✓\033[0m"
FAIL = "\033[31m✗\033[0m"
fails = []


def check(name, cond, detail=""):
    print(f"  {PASS if cond else FAIL} {name}" + (f"  — {detail}" if detail and not cond else ""))
    if not cond:
        fails.append(name)


def main():
    tmp = Path(tempfile.mkdtemp(prefix="cam_e2e_"))
    print(f"\n工作目录: {tmp}\n")

    # ── 准备素材 ──
    print("① 准备素材文件")
    ep1 = tmp / "星舰纪元" / "第1话"
    ep1.mkdir(parents=True)
    for i in range(1, 5):
        p = ep1 / f"第1话_{i:02d}.png"
        Image.new("RGB", (800, 1200), ((i * 50) % 255, 120, 200)).save(p)
    # 一个真实 JPEG，验证类型识别与缩略图
    Image.new("RGB", (800, 1200), (200, 60, 60)).save(ep1 / "05_extra.jpg", "JPEG")
    cover = tmp / "cover.png"
    Image.new("RGB", (600, 900), (20, 30, 60)).save(cover)
    script = tmp / "剧本.txt"
    script.write_text("# 第1话\n\n**船长**：出发。", encoding="utf-8")
    mp3 = tmp / "bgm.mp3"
    mp3.write_bytes(b"\xff\xfb\x90\x00" + b"\x00" * 2000)
    check("素材准备", ep1.is_dir() and cover.exists() and script.exists())

    # ── 空库 ──
    print("\n② 创建空数据库")
    db = Database(tmp / "library.db")
    check("空库统计", db.stats()["assets"] == 0)

    # ── 扫描 ──
    print("\n③ 扫描文件夹")
    found = scan_files(ep1)
    check("识别 5 个文件", len(found) == 5, f"实际 {len(found)}")
    check("类型推断为 comic_page", all(t == AssetType.COMIC_PAGE for _, t in found))

    # ── 批量导入（复制模式）──
    print("\n④ 批量导入（复制到资产库）")
    s = db.create_series(Series(name="星舰纪元", author="陈墨"))
    rep = import_folder(db, ep1, series=s, series_name="星舰纪元", copy_files=True)
    check("导入 5 项", rep.imported == 5, f"实际 {rep.imported}")
    check("生成 5 张缩略图", rep.thumb_generated == 5, f"实际 {rep.thumb_generated}")
    check("文件已复制到资产库",
          all(Path(a.file_path).parent.name == "comic_page" for a in db.list_assets()))
    pages = db.list_assets(order_by="page_index", reverse=False)
    check("页序自然排序", [p.page_index for p in pages] == [1, 2, 3, 4, 5],
          str([p.page_index for p in pages]))
    check("原文件未被破坏", ep1.is_dir())

    # ── 单文件导入（引用模式）──
    print("\n⑤ 单文件导入（引用原路径）")
    a_cover = import_file(db, cover, series_id=s.id, asset_type=AssetType.COVER, copy_files=False)
    check("封面导入", a_cover is not None and a_cover.type == AssetType.COVER)
    check("引用模式路径不变", a_cover.file_path == str(cover))
    check("封面缩略图已生成",
          thumbnail.thumb_path(a_cover.id, Path(db.db_path).parent).exists())

    # ── 文本资产 ──
    print("\n⑥ 文本资产")
    a_script = import_file(db, script, series_id=s.id, asset_type=AssetType.SCRIPT,
                           copy_files=True)
    check("剧本导入", a_script is not None and a_script.type == AssetType.SCRIPT)
    check("正文已提取", "船长" in (a_script.content or "") or "船长" in a_script.description,
          f"content={a_script.content!r}")

    # ── 音频资产 ──
    print("\n⑦ 音频资产")
    a_audio = import_file(db, mp3, series_id=s.id, asset_type=AssetType.AUDIO, copy_files=True)
    check("音频导入", a_audio is not None)
    dur = thumbnail.audio_duration(a_audio.file_path)
    check("音频时长可解析", dur is None or dur > 0, f"dur={dur}")

    # ── 章节 ──
    print("\n⑧ 章节")
    c = db.create_chapter(Chapter(series_id=s.id, volume=1, number=1, title="觉醒"))
    check("章节标签", c.label == "第1卷 · 第1话", c.label)

    # ── 编辑资产 ──
    print("\n⑨ 编辑资产")
    a = db.get_asset(pages[0].id)
    a.title = "第1页 · 修正版"
    a.tags = ["战斗", "主角"]
    a.description = "开场分镜"
    a.page_index = 1
    db.update_asset(a)
    got = db.get_asset(a.id)
    check("标题已更新", got.title == "第1页 · 修正版")
    check("标签已更新", got.tags == ["战斗", "主角"])
    check("标签自动注册", {t.name for t in db.list_tags()} >= {"战斗", "主角"})
    check("更新时间戳递增", got.updated_at >= a.updated_at)

    # ── 搜索 ──
    print("\n⑩ 搜索")
    check("标题搜索", len(db.list_assets(search="修正版")) == 1)
    check("正文搜索", len(db.list_assets(search="船长")) >= 1)
    check("标签搜索", len(db.list_assets(tag="战斗")) == 1)
    check("多条件组合",
          len(db.list_assets(asset_type=AssetType.COMIC_PAGE, search="第")) >= 3)

    # ── 分页 ──
    print("\n⑪ 分页")
    total = db.count_assets()
    check("总数", total == 8, f"实际 {total}")
    p1 = db.list_assets(limit=5, offset=0, order_by="id", reverse=False)
    p2 = db.list_assets(limit=5, offset=5, order_by="id", reverse=False)
    check("第一页 5 项", len(p1) == 5)
    check("第二页 3 项", len(p2) == 3)
    check("无重复", {x.id for x in p1}.isdisjoint({x.id for x in p2}))

    # ── 统计 ──
    print("\n⑫ 统计")
    st = db.stats()
    check("资产数一致", st["assets"] == total)
    check("类型统计求和", sum(st[t.value] for t in AssetType) == total)

    # ── 备份 ──
    print("\n⑬ 备份")
    bak = db.backup(tmp / "backup")
    check("备份文件生成", Path(bak).exists())
    check("备份体积 > 0", Path(bak).stat().st_size > 0)
    db2 = Database(bak)
    check("备份可读取", db2.stats()["assets"] == total)
    db2.close()

    # ── 导出 / 迁移 ──
    print("\n⑭ 导出 → 迁移 → 还原")
    jpath = export_library(db, tmp / "export.json")
    check("JSON 已导出", Path(jpath).exists())

    db3 = Database(tmp / "new.db")
    rep3 = import_library(db3, jpath, base_dir=str(tmp))
    check("迁移导入成功", rep3.imported == total, f"实际 {rep3.imported}")
    check("迁移后资产数", db3.count_assets() == total)
    check("系列已迁移", len(db3.list_series()) == 1)
    check("章节已迁移", len(db3.list_chapters()) == 1)
    got3 = db3.list_assets(asset_type=AssetType.SCRIPT)[0]
    check("正文完整迁移", "船长" in (got3.content or ""))
    tagged = [a for a in db3.list_assets(asset_type=AssetType.COMIC_PAGE)
              if a.tags == ["战斗", "主角"]]
    check("标签迁移", len(tagged) == 1, f"命中 {len(tagged)}")

    # ── 删除 ──
    print("\n⑮ 删除与级联")
    aid = db.list_assets(asset_type=AssetType.COVER)[0].id
    fpath = db.get_asset(aid).file_path
    db.delete_asset(aid)
    check("记录已删除", db.get_asset(aid) is None)
    check("文件未被删除", Path(fpath).exists())
    check("计数减少", db.count_assets() == total - 1)

    db.delete_series(s.id)
    check("系列删除后资产保留（解关联）", db.count_assets() == total - 1)
    check("资产 series_id 置空", db.list_assets()[0].series_id is None)

    # ── 关闭 ──
    print("\n⑯ 清理")
    db.close()
    db3.close()
    check("数据库文件保留", Path(db.db_path).exists())

    shutil.rmtree(tmp, ignore_errors=True)

    print(f"\n{'=' * 50}")
    if fails:
        print(f"{FAIL} {len(fails)} 项失败: {fails}")
        return 1
    print(f"{PASS} 端到端验证全部通过（{16} 个环节）")
    return 0


if __name__ == "__main__":
    sys.exit(main())
