import unittest

from gnos.chunking.api import ChunkerContext, ManifestChunk
from gnos.chunking.core_chunkers import FramedSequentialV1, IdentityV1, SequentialV1


class TestIdentityV1(unittest.TestCase):
    def test_roundtrip(self) -> None:
        c = IdentityV1()
        data = b"hello\n"
        chunks = c.split(data, {}, ChunkerContext()).chunks
        self.assertEqual(len(chunks), 1)
        self.assertEqual(chunks[0].data, data)
        out = c.reconstruct([ManifestChunk(data=chunks[0].data, entry={})], {})
        self.assertEqual(out, data)

    def test_requires_one_chunk(self) -> None:
        c = IdentityV1()
        with self.assertRaises(ValueError):
            c.reconstruct([], {})


class TestSequentialV1(unittest.TestCase):
    def test_roundtrip(self) -> None:
        c = SequentialV1()
        data = b"hello world"
        chunks = c.split(data, {"chunk_size": 5}, ChunkerContext()).chunks
        out = c.reconstruct([ManifestChunk(data=ch.data, entry={}) for ch in chunks], {"chunk_size": 5})
        self.assertEqual(out, data)

    def test_empty_roundtrip(self) -> None:
        c = SequentialV1()
        chunks = c.split(b"", {"chunk_size": 5}, ChunkerContext()).chunks
        self.assertEqual(len(chunks), 1)
        out = c.reconstruct([ManifestChunk(data=chunks[0].data, entry={})], {"chunk_size": 5})
        self.assertEqual(out, b"")

    def test_invalid_params(self) -> None:
        c = SequentialV1()
        with self.assertRaises(ValueError):
            c.split(b"x", {}, ChunkerContext())


class TestFramedSequentialV1(unittest.TestCase):
    def test_roundtrip(self) -> None:
        c = FramedSequentialV1()
        data = b"hello world"
        chunks = c.split(data, {"max_payload_bytes": 5}, ChunkerContext()).chunks
        out = c.reconstruct([ManifestChunk(data=ch.data, entry={}) for ch in chunks], {"max_payload_bytes": 5})
        self.assertEqual(out, data)

    def test_roundtrip_empty(self) -> None:
        c = FramedSequentialV1()
        chunks = c.split(b"", {"max_payload_bytes": 5}, ChunkerContext()).chunks
        self.assertEqual(len(chunks), 1)
        out = c.reconstruct([ManifestChunk(data=chunks[0].data, entry={})], {"max_payload_bytes": 5})
        self.assertEqual(out, b"")

    def test_invalid_magic(self) -> None:
        c = FramedSequentialV1()
        chunks = c.split(b"hello", {"max_payload_bytes": 5}, ChunkerContext()).chunks
        bad = b"XXXX" + chunks[0].data[4:]
        with self.assertRaises(ValueError):
            c.reconstruct([ManifestChunk(data=bad, entry={})], {"max_payload_bytes": 5})

    def test_invalid_params(self) -> None:
        c = FramedSequentialV1()
        with self.assertRaises(ValueError):
            c.split(b"x", {}, ChunkerContext())


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