import pytest
from flexoentity.id_factory import FlexOID


# ─────────────────────────────────────────────────────────────────────────────
# Valid construction via from_strings
# ─────────────────────────────────────────────────────────────────────────────
def test_from_strings_valid():
    oid = FlexOID.from_strings(
        domain_id="GEN_GENERIC",
        entity_type="I",
        date="251101",
        hash_part="A1B2C3D4E5F6",
        version="001",
        state="D",
    )

    assert isinstance(oid, FlexOID)
    assert str(oid) == "GEN_GENERIC-I251101-A1B2C3D4E5F6@001D"

    assert oid.domain_id == "GEN_GENERIC"
    assert oid.entity_type == "I"
    assert oid.date_str == "251101"
    assert oid.hash_part == "A1B2C3D4E5F6"
    assert oid.version == 1
    assert oid.state_code == "D"


# ─────────────────────────────────────────────────────────────────────────────
# from_dict should delegate to from_strings
# ─────────────────────────────────────────────────────────────────────────────
def test_from_dict_valid():
    data = {
        "domain_id": "AF",
        "entity_type": "C",
        "date": "250101",
        "hash": "ABCDEF123456",
        "version": "003",
        "state": "A",
    }

    oid = FlexOID.from_dict(data)

    assert isinstance(oid, FlexOID)
    assert str(oid) == "AF-C250101-ABCDEF123456@003A"


# ─────────────────────────────────────────────────────────────────────────────
# Missing dict fields must fail loudly
# ─────────────────────────────────────────────────────────────────────────────
def test_from_dict_missing_fields():
    incomplete = {
        "domain": "AF",
        "entity_type": "C",
        # missing: date, hash, version, state
    }

    with pytest.raises(ValueError):
        FlexOID.from_dict(incomplete)


# ─────────────────────────────────────────────────────────────────────────────
# Invalid strings should be rejected in from_strings
# ─────────────────────────────────────────────────────────────────────────────
@pytest.mark.parametrize("domain", ["geN", "GEN!", "GEN-", "", None])
def test_from_strings_invalid_domain(domain):
    with pytest.raises(ValueError):
        FlexOID.from_strings(
            domain_id=domain,
            entity_type="I",
            date="241001",
            hash_part="AABBCCDDEEFF",
            version="001",
            state="D",
        )


@pytest.mark.parametrize("etype", ["", "ITEM", "i", "aa"])
def test_from_strings_invalid_entity_type(etype):
    with pytest.raises(ValueError):
        FlexOID.from_strings(
            domain_id="GEN",
            entity_type=etype,
            date="241001",
            hash_part="AABBCCDDEEFF",
            version="001",
            state="D",
        )


@pytest.mark.parametrize("date", ["20241001", "2410", "ABCDEF", None])
def test_from_strings_invalid_date(date):
    with pytest.raises(ValueError):
        FlexOID.from_strings(
            domain_id="GEN",
            entity_type="I",
            date=date,
            hash_part="AABBCCDDEEFF",
            version="001",
            state="D",
        )


@pytest.mark.parametrize("hash_part", ["abc123", "ZZZZZZZZ", "GHIJKL", "", None])
def test_from_strings_invalid_hash(hash_part):
    with pytest.raises(ValueError):
        FlexOID.from_strings(
            domain_id="GEN",
            entity_type="I",
            date="241001",
            hash_part=hash_part,
            version="001",
            state="D",
        )


@pytest.mark.parametrize("version", ["1", "01", "1000", "0A1", "abc", None])
def test_from_strings_invalid_version(version):
    with pytest.raises(ValueError):
        FlexOID.from_strings(
            domain_id="GEN",
            entity_type="I",
            date="241001",
            hash_part="AABBCCDDEEFF",
            version=version,
            state="D",
        )


@pytest.mark.parametrize("state", ["d", "DD", "1", "", None])
def test_from_strings_invalid_state(state):
    with pytest.raises(ValueError):
        FlexOID.from_strings(
            domain_id="GEN",
            entity_type="I",
            date="241001",
            hash_part="AABBCCDDEEFF",
            version="001",
            state=state,
        )
