import hashlib

import pytest

from machine_backup.manifest import (
    add_archive_block,
    build_manifest,
    hash_file,
    hash_tree,
    read_manifest,
    write_manifest,
)
from machine_backup.modules.base import Artifact, ModuleResult, ModuleStatus


def test_hash_file_known_value(tmp_path):
    f = tmp_path / "x"
    f.write_bytes(b"payload")
    assert hash_file(f) == hashlib.sha256(b"payload").hexdigest()


def test_hash_tree_relative_sorted(tmp_path):
    (tmp_path / "sub").mkdir()
    (tmp_path / "sub" / "b.txt").write_text("b")
    (tmp_path / "a.txt").write_text("a")
    arts = hash_tree(tmp_path, prefix="shell")
    assert [a.path for a in arts] == ["shell/a.txt", "shell/sub/b.txt"]


def test_build_manifest_status_partial_and_roundtrip(tmp_path):
    results = [
        ModuleResult(
            "postgres",
            ModuleStatus.OK,
            artifacts=[Artifact("postgres/g.sql", "0" * 64, 10, True)],
            duration_s=1.0,
            meta={},
        ),
        ModuleResult("homebrew", ModuleStatus.SKIPPED, error="brew absent"),
    ]
    m = build_manifest(
        results,
        tool_version="0.1.0",
        hostname="h",
        macos_version="15.5",
        created_at="2026-08-05T14:30:12+02:00",
    )
    assert m["status"] == "partial"
    assert m["schema_version"] == 1
    assert m["modules"]["postgres"]["artifacts"][0]["sensitive"] is True
    assert m["modules"]["homebrew"]["error"] == "brew absent"
    assert "archive" not in m

    p = tmp_path / "manifest.json"
    write_manifest(m, p)
    assert read_manifest(p) == m


def test_build_manifest_complete_when_all_ok():
    m = build_manifest(
        [ModuleResult("shell", ModuleStatus.OK)],
        tool_version="0.1.0",
        hostname="h",
        macos_version="15.5",
        created_at="2026-08-05T14:30:12+02:00",
    )
    assert m["status"] == "complete"
    assert m["modules"]["shell"]["status"] == "ok"


def test_add_archive_block_does_not_mutate_source(tmp_path):
    arch = tmp_path / "snapshot.tar.zst.age"
    arch.write_bytes(b"xyz")
    source = {"schema_version": 1, "modules": {}, "status": "complete"}
    m2 = add_archive_block(source, arch)
    assert m2["archive"]["file"] == "snapshot.tar.zst.age"
    assert m2["archive"]["size"] == 3
    assert len(m2["archive"]["sha256"]) == 64
    assert "archive" not in source


def test_read_manifest_rejects_unknown_schema(tmp_path):
    p = tmp_path / "manifest.json"
    p.write_text('{"schema_version": 99}')
    with pytest.raises(ValueError, match="schema"):
        read_manifest(p)
