import tempfile
import unittest
from pathlib import Path
from unittest import mock

from gnos.core.add import add_path, AddError
from gnos.core.store import ObjectStore
from gnos.chunking.api import Chunker, ChunkerContext, ManifestChunk, SplitChunk, SplitResult


class TestAddAtomic(unittest.TestCase):
    def test_add_atomic_no_objects_on_failure(self) -> None:
        with tempfile.TemporaryDirectory() as tmp:
            root = Path(tmp)
            store = ObjectStore(root / ".gnos")
            store.init()
            path = root / "a.txt"
            path.write_text("hello\n", encoding="utf-8")

            class _BadChunker(Chunker):
                name = "bad-v1"

                def split(self, data: bytes, params, _ctx: ChunkerContext):
                    return SplitResult(chunks=[SplitChunk(data=data)], params=params)

                def reconstruct(self, _chunks: list[ManifestChunk], _params):
                    return b"bad"

            bad_method = _BadChunker()

            with mock.patch("gnos.core.add.get_method", return_value=bad_method):
                with self.assertRaises(AddError):
                    add_path(path, store, format="text", chunking="bad-v1")

            # No objects should be committed on failure.
            objects = list((root / ".gnos" / "objects").rglob("*"))
            files = [p for p in objects if p.is_file()]
            self.assertEqual(len(files), 0)
            self.assertFalse((root / ".gnos" / "index.json").exists())


if __name__ == "__main__":
    unittest.main()
