#!/usr/bin/env python3

# tests/test_flexoid.py
"""
Test suite for id_factory.FlexOID.

I verify that FlexOID behaves deterministically, validates itself strictly,
and evolves correctly through version and state transitions.
"""

import re
from datetime import datetime, date
import pytest
from logging import Logger
from flexoentity import FlexOID, canonical_seed


logger = Logger(__file__)

# ──────────────────────────────────────────────
# Basic construction and validation
# ──────────────────────────────────────────────

def test_valid_flexoid_parsing():
    fid = FlexOID("GEN-I251101-ABCDEF123456@001D")
    assert isinstance(fid, str)
    assert fid.domain_id == "GEN"
    assert fid.entity_type == "I"
    assert fid.date_str == "251101"
    assert fid.version == 1
    assert fid.state_code == "D"
    assert fid.prefix.endswith("ABCDEF123456")
    assert str(fid).endswith("@001D")


def test_invalid_flexoid_raises():
    with pytest.raises(ValueError):
        FlexOID("INVALIDFORMAT")
    with pytest.raises(ValueError):
        FlexOID("GEN-I251101-ABCDEF@1D")  # bad version width


def test_regex_is_strict():
    pat = FlexOID.OID_PATTERN
    assert re.match(pat, "GEN-I251101-123456ABCDEF@001A")
    assert not re.match(pat, "gen-item251101-123456@001A")  # lowercase not allowed
    assert not re.match(pat, "GEN-I251101-123456@01A")   # wrong digit count


# ──────────────────────────────────────────────
# Generation and deterministic hashing
# ──────────────────────────────────────────────

def test_generate_and_hash_stability(fixed_datetime):
    # Fix the date so test is stable
    fid1 = FlexOID.generate("GEN", "I", "D", "test content")
    fid2 = FlexOID.generate("GEN", "I", "D", "test content")
    assert fid1 == fid2  # deterministic
    assert fid1.hash_part == fid2.hash_part
    assert fid1.domain_id == "GEN"
    assert fid1.entity_type == "I"


def test_safe_generate_collision(monkeypatch):
    # Fake repo that always returns a conflicting item with different seed
    class DummyRepo(dict):
        def get(self, key): return True

    repo = DummyRepo()
    fid = FlexOID.safe_generate("GEN", "I", "D", "abc", repo=repo)
    assert isinstance(fid, FlexOID)
    assert fid.state_code == "D"


# ──────────────────────────────────────────────
# State and version transitions
# ──────────────────────────────────────────────

def test_with_state_creates_new_instance():
    fid = FlexOID("GEN-I251101-ABCDEF123456@001D")
    fid2 = fid.with_state("A")
    assert fid != fid2
    assert fid.version == fid2.version
    assert fid2.state_code == "A"
    assert str(fid2).endswith("@001A")


def test_next_version_increments_properly():
    fid = FlexOID("GEN-I251101-ABCDEF123456@001A")
    fid2 = FlexOID.next_version(fid)
    assert fid2.version == 2
    assert fid2.state_code == fid.state_code
    assert fid.prefix == fid2.prefix


def test_from_oid_and_version_sets_exact_version():
    fid = FlexOID("GEN-I251101-ABCDEF123456@001A")
    fid2 = FlexOID.from_oid_and_version(fid, 10)
    assert fid2.version == 10
    assert fid2.state_code == "A"


def test_clone_new_base_starts_at_one(fixed_datetime):
    fid = FlexOID.clone_new_base("GEN", "I", "D", "clone text")
    assert fid.version == 1
    assert fid.state_code == "D"


# ──────────────────────────────────────────────
# Canonical seed behavior
# ──────────────────────────────────────────────

def test_canonical_seed_for_strings():
    s1 = "  Hello   world "
    s2 = "Hello world"
    assert canonical_seed(s1) == canonical_seed(s2)

# ──────────────────────────────────────────────
# Parsed structure and representations
# ──────────────────────────────────────────────

def test_parsed_returns_expected_dict():
    fid = FlexOID("GEN-I251101-ABCDEF123456@007S")
    data = fid.to_dict()
    assert data["domain_id"] == "GEN"
    assert data["entity_type"] == "I"
    assert data["version"] == 7
    assert data["state"] == "S"
    assert isinstance(data["date"], date)


def test_repr_is_readable():
    fid = FlexOID("GEN-I251101-ABCDEF123456@001D")
    s = repr(fid)
    assert "FlexOID" in s
    assert "GEN-I" in s
