"""PreviewService 单元测试，不依赖数据库或真实 LibreOffice。"""

from __future__ import annotations

from pathlib import Path

import pytest

from dms.services.document_converter import FakeDocumentConverter
from dms.services.preview_service import PreviewService
from dms.storage.paths import UnsafeStoragePathError, preview_cache_path


@pytest.fixture
def storage_root(tmp_path: Path) -> Path:
    root = tmp_path / "dms-storage"
    (root / "preview").mkdir(parents=True)
    (root / "original").mkdir(parents=True)
    return root


@pytest.fixture
def preview_service(storage_root: Path) -> PreviewService:
    return PreviewService(storage_root, FakeDocumentConverter())


def test_preview_cache_path_with_hash_prefix(storage_root: Path) -> None:
    path = preview_cache_path("abcdef123456", storage_root)
    assert path.name == "abcdef123456.pdf"
    assert path.parent.name == "ab"
    assert path.parent.parent.name == "preview"


def test_preview_cache_path_rejects_invalid_hash(storage_root: Path) -> None:
    with pytest.raises(UnsafeStoragePathError):
        preview_cache_path("", storage_root)


def test_validate_cached_pdf_accepts_valid_pdf(
    preview_service: PreviewService, storage_root: Path
) -> None:
    cache = preview_cache_path("validhash", storage_root)
    cache.parent.mkdir(parents=True, exist_ok=True)
    # 生成 fitz 可真正打开的合法最小 PDF，避免仅写入魔数导致验证失败
    import fitz

    doc = fitz.open()
    doc.new_page()
    doc.save(str(cache))
    doc.close()
    assert preview_service.validate_cached_pdf(cache) is True


def test_validate_cached_pdf_rejects_non_pdf(
    preview_service: PreviewService, storage_root: Path
) -> None:
    cache = preview_cache_path("nonpdfhash", storage_root)
    cache.parent.mkdir(parents=True, exist_ok=True)
    cache.write_bytes(b"not a pdf")
    assert preview_service.validate_cached_pdf(cache) is False


def test_validate_cached_pdf_rejects_path_outside_preview(
    preview_service: PreviewService, tmp_path: Path
) -> None:
    outside = tmp_path / "outside.pdf"
    outside.write_bytes(b"%PDF-1.4")
    assert preview_service.validate_cached_pdf(outside) is False


class FakeDocument:
    def __init__(
        self,
        file_extension: str,
        file_hash: str,
        file_relative_path: str,
    ) -> None:
        self.file_extension = file_extension
        self.file_hash = file_hash
        self.file_relative_path = file_relative_path


def test_preview_path_for_pdf_returns_original(
    preview_service: PreviewService, storage_root: Path
) -> None:
    original = storage_root / "original" / "sample.pdf"
    original.write_bytes(b"%PDF-1.4")
    document = FakeDocument("pdf", "pdfhash", "original/sample.pdf")
    path = preview_service.preview_path_for(document)
    assert path == original


def test_preview_path_for_docx_generates_cache(
    preview_service: PreviewService, storage_root: Path
) -> None:
    original = storage_root / "original" / "sample.docx"
    original.write_bytes(b"fake docx content")
    document = FakeDocument("docx", "docxhash", "original/sample.docx")
    path = preview_service.preview_path_for(document)
    assert path.name == "docxhash.pdf"
    assert path.exists()
    assert path.read_bytes().startswith(b"%PDF-")


def test_preview_path_for_doc_uses_cache_on_second_call(
    preview_service: PreviewService, storage_root: Path
) -> None:
    original = storage_root / "original" / "sample.doc"
    original.write_bytes(b"fake doc content")
    document = FakeDocument("doc", "dochash", "original/sample.doc")
    first = preview_service.preview_path_for(document)
    mtime = first.stat().st_mtime
    second = preview_service.preview_path_for(document)
    assert second == first
    assert second.stat().st_mtime == mtime
