"""Tests for the pure backup-manifest schema (mgf.vm.core.operations.manifest)."""

from __future__ import annotations

from datetime import UTC, datetime

import pytest

from mgf.vm.core.exceptions import BackupError
from mgf.vm.core.operations.manifest import (
    FORMAT_VERSION,
    MANIFEST_NAME,
    BackupManifest,
    DiskEntry,
)


def _manifest() -> BackupManifest:
    return BackupManifest(
        format_version=FORMAT_VERSION,
        vm_name="web",
        uuid="11111111-2222-3333-4444-555555555555",
        created_at=datetime(2026, 4, 12, 10, 0, 0, tzinfo=UTC),
        domain_xml="<domain><name>web</name></domain>",
        disks=(
            DiskEntry(target="vda", file="vda.qcow2", sha256="a" * 64),
            DiskEntry(target="vdb", file="vdb.raw", sha256="b" * 64),
        ),
    )


def test_constants() -> None:
    assert FORMAT_VERSION == 1
    assert MANIFEST_NAME == "backup-manifest.json"


def test_to_json_then_from_json_round_trips() -> None:
    original = _manifest()
    restored = BackupManifest.from_json(original.to_json())
    assert restored == original


def test_to_json_preserves_disk_order_and_fields() -> None:
    import json

    payload = json.loads(_manifest().to_json())
    assert payload["format_version"] == 1
    assert payload["vm_name"] == "web"
    assert payload["created_at"] == "2026-04-12T10:00:00+00:00"
    assert [d["target"] for d in payload["disks"]] == ["vda", "vdb"]
    assert payload["disks"][0]["file"] == "vda.qcow2"
    assert payload["disks"][0]["sha256"] == "a" * 64


def test_disk_entry_and_manifest_are_frozen() -> None:
    entry = DiskEntry(target="vda", file="vda.qcow2", sha256="a" * 64)
    with pytest.raises(AttributeError):
        entry.target = "vdb"  # type: ignore[misc]
    manifest = _manifest()
    with pytest.raises(AttributeError):
        manifest.vm_name = "other"  # type: ignore[misc]


def test_from_json_rejects_non_json() -> None:
    with pytest.raises(BackupError, match="not valid JSON"):
        BackupManifest.from_json("{not json")


def test_from_json_rejects_missing_key() -> None:
    with pytest.raises(BackupError, match="malformed"):
        BackupManifest.from_json('{"vm_name": "web"}')


def test_from_json_rejects_bad_created_at() -> None:
    raw = (
        '{"format_version": 1, "vm_name": "web", "uuid": "u", '
        '"created_at": "not-a-date", "domain_xml": "<domain/>", "disks": []}'
    )
    with pytest.raises(BackupError, match="malformed"):
        BackupManifest.from_json(raw)


def test_from_json_coerces_scalar_types() -> None:
    raw = (
        '{"format_version": "2", "vm_name": 7, "uuid": "u", '
        '"created_at": "2026-04-12T10:00:00+00:00", "domain_xml": "<domain/>", '
        '"disks": [{"target": "vda", "file": "vda.qcow2", "sha256": "x"}]}'
    )
    manifest = BackupManifest.from_json(raw)
    assert manifest.format_version == 2
    assert manifest.vm_name == "7"
    assert manifest.disks[0].target == "vda"


def test_from_json_empty_disks() -> None:
    raw = (
        '{"format_version": 1, "vm_name": "web", "uuid": "u", '
        '"created_at": "2026-04-12T10:00:00+00:00", "domain_xml": "<domain/>", "disks": []}'
    )
    assert BackupManifest.from_json(raw).disks == ()
