"""Docker 构建输入和镜像载荷分层合同。"""

from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
DOCKERFILE = ROOT / "docker" / "Dockerfile"
RELEASE_WORKFLOW = ROOT / ".github" / "workflows" / "build-v3.yml"
BETA_WORKFLOW = ROOT / ".github" / "workflows" / "beta.yml"


def _read(path: Path) -> str:
    """读取构建合同文件。"""
    return path.read_text(encoding="utf-8")


def test_build_context_excludes_runtime_state_and_keeps_release_inputs() -> None:
    """本地运行数据不得进入构建上下文，发布所需入口必须保留。"""
    dockerignore = _read(ROOT / ".dockerignore")

    for pattern in (
        ".venv/",
        ".worktrees/",
        ".build/",
        ".agent-work/",
        ".runtime/",
        ".tmp/",
        ".cache/",
        "node_modules/",
        "public/",
        ".moviepilot.env",
        ".env",
        ".env.*",
        "**/*.pyc",
        "**/__pycache__/",
        "**/*.pyd",
        "**/*.so",
        "coverage.json",
        "coverage.xml",
        "config/*",
        "app/plugins/**",
        "app/application/site/*.bin",
    ):
        assert pattern in dockerignore

    assert "!config/category.yaml" in dockerignore
    assert "!app/plugins/__init__.py" in dockerignore
    assert "frontend-dist" not in dockerignore


def test_dockerfile_assigns_each_payload_to_an_independent_stage() -> None:
    """高频载荷必须由独立 stage 生成，并在 final 中分别写入目标目录。"""
    dockerfile = _read(DOCKERFILE)

    for stage in (
        "prepare_backend",
        "prepare_frontend",
        "prepare_plugins",
        "prepare_resources",
        "prepare_control",
    ):
        assert f" AS {stage}" in dockerfile

    final_start = dockerfile.index("FROM prepare_package AS final")
    final = dockerfile[final_start:]
    copies = (
        "COPY --link --from=prepare_frontend /public /public",
        "COPY --link --from=prepare_plugins /plugins /app/app/plugins",
        "COPY --link --from=prepare_resources /resources /app/app/application/site",
        "COPY --link --from=prepare_backend /app /app",
    )
    positions = [final.index(copy) for copy in copies]

    assert positions == sorted(positions)
    for copy in copies:
        assert final.count(copy) == 1
    assert "COPY --from=prepare_control /bundle/entrypoint.sh /entrypoint.sh" in final
    assert "RUN rm -rf /app/frontend-dist" in dockerfile


def test_plugin_runtime_updates_preserve_legacy_base_entrypoint() -> None:
    """更新和性能覆盖镜像必须保留旧插件导入 _PluginBase 所需的兼容入口。"""
    update_script = _read(ROOT / "docker" / "update.sh")
    perf_script = _read(ROOT / "scripts" / "perf" / "moviepilot_docker_ab.py")

    assert 'rm -f "${stage_plugin_dir}/__init__.py"' not in update_script
    assert "rm -f /frozen/plugins/__init__.py" not in perf_script


def test_release_workflows_pin_and_record_external_payload_identities() -> None:
    """正式与 Beta 构建都必须以真实制品身份驱动缓存并写入镜像标签。"""
    for workflow_path in (RELEASE_WORKFLOW, BETA_WORKFLOW):
        workflow = _read(workflow_path)

        for build_arg in (
            "MOVIEPILOT_FRONTEND_VERSION=",
            "MOVIEPILOT_FRONTEND_SHA256=",
            "MOVIEPILOT_PLUGINS_REF=",
            "MOVIEPILOT_RESOURCES_REF=",
        ):
            assert build_arg in workflow

        for label in (
            "org.moviepilot.source-revision=",
            "org.moviepilot.frontend-version=",
            "org.moviepilot.frontend-digest=",
            "org.moviepilot.plugins-revision=",
            "org.moviepilot.resources-revision=",
            "org.moviepilot.plugin-market-wiki-revision=",
            "org.moviepilot.models-catalog-digest=",
        ):
            assert label in workflow

        assert "git ls-remote https://github.com/jxxghp/MoviePilot-Plugins.git" in workflow
        assert "git ls-remote https://github.com/jxxghp/MoviePilot-Resources.git" in workflow
        assert "sha256:*) frontend_sha256=" in workflow
        assert "^[0-9a-f]{40}$" in workflow
        assert "^[0-9a-f]{64}$" in workflow


def test_same_version_rebuild_identity_is_not_derived_from_image_tag() -> None:
    """重复发布同一版本时，缓存身份必须来自源码和制品而不是镜像 Tag。"""
    release_workflow = _read(RELEASE_WORKFLOW)

    assert "SOURCE_COMMIT=$(git rev-parse HEAD)" in release_workflow
    assert "org.moviepilot.source-revision=${{ env.SOURCE_COMMIT }}" in release_workflow
    assert (
        "org.moviepilot.release-snapshot-revision="
        "${{ steps.release_snapshot.outputs.release_commit }}" in release_workflow
    )
    assert "type=raw,value=${{ env.app_version }}" in release_workflow
    assert "MOVIEPILOT_PLUGINS_REF=${{ steps.payloads.outputs.plugins_revision }}" in release_workflow
    assert "MOVIEPILOT_RESOURCES_REF=${{ steps.payloads.outputs.resources_revision }}" in release_workflow


def test_custom_frontend_directory_is_stable_but_artifacts_remain_untracked() -> None:
    """干净 checkout 可直接构建，自定义前端产物仍保持本地状态。"""
    gitignore = _read(ROOT / ".gitignore")
    dockerfile = _read(DOCKERFILE)

    assert (ROOT / "frontend-dist" / ".gitkeep").is_file()
    assert "frontend-dist/*" in gitignore
    assert "!frontend-dist/.gitkeep" in gitignore
    assert "COPY frontend-dist/ /tmp/frontend-dist/" in dockerfile
    assert "! -name '.gitkeep'" in dockerfile
