"""S0 — unit tests for the opaque VolumeId / SnapshotId codecs."""

from __future__ import annotations

import pytest
from mgf.vm.core.exceptions import SnapshotNotFound, VolumeNotFound
from mgf.vm.core.ids import SnapshotId, VolumeId

from mgf.vm.libvirt._volume_ids import (
    SnapshotRef,
    VolumeRef,
    decode_snapshot_id,
    decode_volume_id,
    encode_snapshot_id,
    encode_volume_id,
)


def test_volume_id_round_trip_plain() -> None:
    vid = encode_volume_id("default", "disk0")
    assert isinstance(vid, VolumeId)
    ref = decode_volume_id(vid)
    assert ref == VolumeRef(pool="default", name="disk0")


def test_volume_id_round_trip_with_delimiters() -> None:
    # Pool / volume names containing the structural chars must survive.
    vid = encode_volume_id("pool/with:weird", "vol/name:x")
    ref = decode_volume_id(vid)
    assert ref.pool == "pool/with:weird"
    assert ref.name == "vol/name:x"


def test_volume_id_is_opaque_no_raw_pair() -> None:
    # The encoded string must not expose a bare "pool/name" without the tag.
    vid = encode_volume_id("default", "disk0")
    assert vid.value.startswith("lvpool:")


def test_decode_volume_id_rejects_foreign_id() -> None:
    with pytest.raises(VolumeNotFound):
        decode_volume_id(VolumeId("raw:/dev/sda"))


def test_decode_volume_id_rejects_malformed() -> None:
    with pytest.raises(VolumeNotFound):
        decode_volume_id(VolumeId("lvpool:noseparator"))


def test_snapshot_id_round_trip() -> None:
    sid = encode_snapshot_id("default", "disk0", "snap1")
    assert isinstance(sid, SnapshotId)
    ref = decode_snapshot_id(sid)
    assert ref == SnapshotRef(pool="default", volume="disk0", name="snap1")


def test_snapshot_ref_volume_ref() -> None:
    ref = decode_snapshot_id(encode_snapshot_id("p", "v", "s"))
    assert ref.volume_ref == VolumeRef(pool="p", name="v")


def test_decode_snapshot_id_rejects_foreign() -> None:
    with pytest.raises(SnapshotNotFound):
        decode_snapshot_id(SnapshotId("lvpool:default/disk0"))


def test_decode_snapshot_id_rejects_malformed() -> None:
    with pytest.raises(SnapshotNotFound):
        decode_snapshot_id(SnapshotId("lvsnap:onlyone"))


def test_snapshot_id_with_delimiters() -> None:
    sid = encode_snapshot_id("p/o:ol", "v/o:l", "s/n:ap")
    ref = decode_snapshot_id(sid)
    assert ref == SnapshotRef(pool="p/o:ol", volume="v/o:l", name="s/n:ap")
