"""Additional tests for create module."""

import time

import pytest

from ect import Payload, create, generate_key, CreateOptions, default_create_options


def test_default_create_options():
    opts = default_create_options()
    assert opts.key_id == ""


def test_create_errors():
    key = generate_key()
    p = Payload(iss="i", aud=["a"], iat=1, exp=2, jti="j", exec_act="e", pred=[])
    with pytest.raises(ValueError, match="KeyID|required"):
        create(p, key, CreateOptions(key_id=""))
    with pytest.raises((ValueError, TypeError, AttributeError)):
        create(None, key, CreateOptions(key_id="k"))


def test_create_optional_pol():
    key = generate_key()
    now = int(time.time())
    p = Payload(
        iss="iss", aud=["a"], iat=now, exp=now + 3600,
        jti="jti-nopol", exec_act="act", pred=[],
    )
    compact = create(p, key, CreateOptions(key_id="kid"))
    assert compact


def test_create_validation_errors():
    key = generate_key()
    base = dict(iss="i", aud=["a"], iat=1, exp=2, jti="j", exec_act="e", pred=[])
    with pytest.raises(ValueError, match="iss"):
        create(Payload(**{**base, "iss": ""}), key, CreateOptions(key_id="k"))
    with pytest.raises(ValueError, match="aud"):
        create(Payload(**{**base, "aud": []}), key, CreateOptions(key_id="k"))
    with pytest.raises(ValueError, match="jti"):
        create(Payload(**{**base, "jti": ""}), key, CreateOptions(key_id="k"))
    with pytest.raises(ValueError, match="exec_act"):
        create(Payload(**{**base, "exec_act": ""}), key, CreateOptions(key_id="k"))


def test_create_ext_compensation_reason_requires_required():
    key = generate_key()
    p = Payload(
        iss="i", aud=["a"], iat=1, exp=2, jti="j", exec_act="e", pred=[],
        ext={"compensation_reason": "rollback", "compensation_required": False},
    )
    with pytest.raises(ValueError, match="compensation_required"):
        create(p, key, CreateOptions(key_id="k"))


def test_create_zero_expiry_uses_default():
    key = generate_key()
    p = Payload(iss="i", aud=["a"], iat=0, exp=0, jti="j", exec_act="e", pred=[])
    compact = create(p, key, CreateOptions(key_id="k", default_expiry_sec=300))
    assert compact
    # create() works on a copy; decode the token to verify defaults were applied
    import jwt
    claims = jwt.decode(compact, options={"verify_signature": False})
    assert claims["exp"] > claims["iat"]


def test_create_validate_uuids_rejects_non_uuid_jti():
    key = generate_key()
    now = int(time.time())
    p = Payload(iss="i", aud=["a"], iat=now, exp=now + 3600, jti="not-a-uuid", exec_act="e", pred=[])
    with pytest.raises(ValueError, match="jti must be UUID"):
        create(p, key, CreateOptions(key_id="k", validate_uuids=True))


def test_create_max_pred_length():
    key = generate_key()
    now = int(time.time())
    p = Payload(iss="i", aud=["a"], iat=now, exp=now + 3600, jti="550e8400-e29b-41d4-a716-446655440000", exec_act="e", pred=["p1", "p2"])
    with pytest.raises(ValueError, match="pred exceeds max length"):
        create(p, key, CreateOptions(key_id="k", max_pred_length=1))


def test_create_ext_size_rejected():
    from ect.validate import EXT_MAX_SIZE
    key = generate_key()
    now = int(time.time())
    p = Payload(
        iss="i", aud=["a"], iat=now, exp=now + 3600, jti="550e8400-e29b-41d4-a716-446655440000", exec_act="e", pred=[],
        ext={"x": "y" * (EXT_MAX_SIZE - 5)},
    )
    with pytest.raises(ValueError, match="ext exceeds max size"):
        create(p, key, CreateOptions(key_id="k"))
