"""Tests for act.lifecycle module."""

import time
import uuid

import pytest

from act.crypto import generate_ed25519_keypair, sign
from act.errors import ACTCapabilityError, ACTPhaseError
from act.lifecycle import transition_to_record
from act.token import (
    ACTMandate,
    ACTRecord,
    Capability,
    Delegation,
    ErrorClaim,
    TaskClaim,
    decode_jws,
    encode_jws,
)
from act.crypto import verify


@pytest.fixture
def keys():
    iss_priv, iss_pub = generate_ed25519_keypair()
    sub_priv, sub_pub = generate_ed25519_keypair()
    return iss_priv, iss_pub, sub_priv, sub_pub


@pytest.fixture
def mandate(keys):
    iss_priv, _, _, _ = keys
    m = ACTMandate(
        alg="EdDSA", kid="iss-key",
        iss="agent-a", sub="agent-b", aud="agent-b",
        iat=1772064000, exp=1772064900,
        jti=str(uuid.uuid4()),
        task=TaskClaim(purpose="test"),
        cap=[Capability(action="read.data"), Capability(action="write.result")],
        delegation=Delegation(depth=0, max_depth=2, chain=[]),
    )
    return m


class TestTransitionToRecord:
    def test_basic_transition(self, mandate, keys):
        _, _, sub_priv, sub_pub = keys
        record, compact = transition_to_record(
            mandate, sub_kid="sub-key", sub_private_key=sub_priv,
            exec_act="read.data", par=[], status="completed",
        )
        assert isinstance(record, ACTRecord)
        assert record.exec_act == "read.data"
        assert record.kid == "sub-key"
        assert record.iss == mandate.iss  # preserved
        # Verify signature
        _, _, sig, si = decode_jws(compact)
        verify(sub_pub, sig, si)

    def test_with_hashes(self, mandate, keys):
        _, _, sub_priv, _ = keys
        record, _ = transition_to_record(
            mandate, sub_kid="k", sub_private_key=sub_priv,
            exec_act="write.result", par=[], status="completed",
            inp_hash="abc", out_hash="def",
        )
        assert record.inp_hash == "abc"
        assert record.out_hash == "def"

    def test_with_error(self, mandate, keys):
        _, _, sub_priv, _ = keys
        record, _ = transition_to_record(
            mandate, sub_kid="k", sub_private_key=sub_priv,
            exec_act="read.data", par=[], status="failed",
            err=ErrorClaim(code="timeout", detail="request timed out"),
        )
        assert record.status == "failed"
        assert record.err is not None
        assert record.err.code == "timeout"

    def test_rejects_bad_exec_act(self, mandate, keys):
        _, _, sub_priv, _ = keys
        with pytest.raises(ACTCapabilityError):
            transition_to_record(
                mandate, sub_kid="k", sub_private_key=sub_priv,
                exec_act="delete.everything", par=[],
            )

    def test_preserves_phase1_claims(self, mandate, keys):
        _, _, sub_priv, _ = keys
        record, _ = transition_to_record(
            mandate, sub_kid="k", sub_private_key=sub_priv,
            exec_act="read.data", par=[], status="completed",
        )
        assert record.iss == mandate.iss
        assert record.sub == mandate.sub
        assert record.aud == mandate.aud
        assert record.iat == mandate.iat
        assert record.exp == mandate.exp
        assert record.jti == mandate.jti
        assert record.task == mandate.task
        assert record.cap == mandate.cap
