"""Tests for rbsp.indexer.preindex -- _make_sig_id, IndexProgress utilities."""

import os
import sys
import unittest

sys.path.insert(0, os.path.dirname(__file__))
from conftest import RBSPTestCase

from rbsp.indexer.preindex import _make_sig_id, IndexProgress


# ---------------------------------------------------------------------------
# _make_sig_id
# ---------------------------------------------------------------------------

class TestMakeSigId(unittest.TestCase):
    """_make_sig_id determinism and uniqueness."""

    def test_deterministic_same_content(self):
        content = b"hello world"
        id1 = _make_sig_id(content)
        id2 = _make_sig_id(content)
        self.assertEqual(id1, id2)

    def test_different_content_different_ids(self):
        id_a = _make_sig_id(b"content A")
        id_b = _make_sig_id(b"content B")
        self.assertNotEqual(id_a, id_b)

    def test_returns_hex_string(self):
        sig_id = _make_sig_id(b"data")
        # BLAKE2b with digest_size=16 -> 32 hex chars
        self.assertEqual(len(sig_id), 32)
        # All characters are valid hex
        int(sig_id, 16)  # raises ValueError if not valid hex

    def test_empty_content(self):
        sig_id = _make_sig_id(b"")
        self.assertIsInstance(sig_id, str)
        self.assertEqual(len(sig_id), 32)

    def test_large_content(self):
        sig_id = _make_sig_id(b"x" * 10_000_000)
        self.assertEqual(len(sig_id), 32)

    def test_binary_content(self):
        sig_id = _make_sig_id(bytes(range(256)))
        self.assertEqual(len(sig_id), 32)

    def test_single_byte_difference(self):
        id1 = _make_sig_id(b"\x00")
        id2 = _make_sig_id(b"\x01")
        self.assertNotEqual(id1, id2)


# ---------------------------------------------------------------------------
# IndexProgress -- percent
# ---------------------------------------------------------------------------

class TestIndexProgressPercent(unittest.TestCase):
    """IndexProgress.percent property."""

    def test_zero_total_returns_zero(self):
        p = IndexProgress()
        self.assertEqual(p.percent, 0.0)

    def test_half_done(self):
        p = IndexProgress()
        p.total_files = 100
        p.processed_files = 50
        self.assertAlmostEqual(p.percent, 50.0)

    def test_fully_done(self):
        p = IndexProgress()
        p.total_files = 200
        p.processed_files = 200
        self.assertAlmostEqual(p.percent, 100.0)

    def test_one_of_three(self):
        p = IndexProgress()
        p.total_files = 3
        p.processed_files = 1
        self.assertAlmostEqual(p.percent, 100.0 / 3, places=4)


# ---------------------------------------------------------------------------
# IndexProgress -- files_per_second
# ---------------------------------------------------------------------------

class TestIndexProgressFilesPerSecond(unittest.TestCase):
    """IndexProgress.files_per_second property."""

    def test_zero_elapsed_returns_zero(self):
        p = IndexProgress()
        p.processed_files = 10
        p.elapsed = 0.0
        self.assertEqual(p.files_per_second, 0.0)

    def test_normal_rate(self):
        p = IndexProgress()
        p.processed_files = 500
        p.elapsed = 2.0
        self.assertAlmostEqual(p.files_per_second, 250.0)

    def test_one_file_one_second(self):
        p = IndexProgress()
        p.processed_files = 1
        p.elapsed = 1.0
        self.assertAlmostEqual(p.files_per_second, 1.0)


# ---------------------------------------------------------------------------
# IndexProgress -- __repr__
# ---------------------------------------------------------------------------

class TestIndexProgressRepr(unittest.TestCase):
    """IndexProgress.__repr__ output."""

    def test_repr_contains_counts(self):
        p = IndexProgress()
        p.total_files = 100
        p.processed_files = 50
        p.indexed_files = 40
        p.skipped_files = 8
        p.error_files = 2
        p.elapsed = 5.0
        r = repr(p)
        self.assertIn("50/100", r)
        self.assertIn("50.0%", r)
        self.assertIn("indexed=40", r)
        self.assertIn("skipped=8", r)
        self.assertIn("errors=2", r)
        self.assertIn("files/s", r)

    def test_repr_zero_state(self):
        p = IndexProgress()
        r = repr(p)
        self.assertIn("0/0", r)
        self.assertIn("0.0%", r)

    def test_repr_returns_string(self):
        p = IndexProgress()
        self.assertIsInstance(repr(p), str)


# ---------------------------------------------------------------------------
# IndexProgress -- defaults
# ---------------------------------------------------------------------------

class TestIndexProgressDefaults(unittest.TestCase):
    """IndexProgress initial defaults."""

    def test_all_zeros(self):
        p = IndexProgress()
        self.assertEqual(p.total_files, 0)
        self.assertEqual(p.processed_files, 0)
        self.assertEqual(p.indexed_files, 0)
        self.assertEqual(p.skipped_files, 0)
        self.assertEqual(p.error_files, 0)
        self.assertEqual(p.start_time, 0.0)
        self.assertEqual(p.elapsed, 0.0)


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