"""ACT Phase 1 to Phase 2 transition logic.

Handles the transition from Authorization Mandate to Execution Record,
including re-signing by the executing agent (sub).

Reference: ACT §3.2, §3.3 (Lifecycle State Machine).
"""

from __future__ import annotations

import time
from typing import Any

from .crypto import PrivateKey, sign as crypto_sign
from .errors import ACTCapabilityError, ACTPhaseError, ACTValidationError
from .token import (
    ACTMandate,
    ACTRecord,
    ErrorClaim,
    encode_jws,
)


def transition_to_record(
    mandate: ACTMandate,
    *,
    sub_kid: str,
    sub_private_key: PrivateKey,
    exec_act: str,
    pred: list[str] | None = None,
    exec_ts: int | None = None,
    status: str = "completed",
    inp_hash: str | None = None,
    out_hash: str | None = None,
    err: ErrorClaim | None = None,
) -> tuple[ACTRecord, str]:
    """Transition a Phase 1 mandate to a Phase 2 execution record.

    The executing agent (sub) adds execution claims and re-signs the
    complete token with its own private key. The kid in the Phase 2
    JOSE header MUST reference sub's key, not iss's key.

    All Phase 1 claims are preserved unchanged in the Phase 2 token.

    Reference: ACT §3.2, §8.2 step 17.

    Args:
        mandate: The Phase 1 ACTMandate to transition.
        sub_kid: The kid for the sub agent's signing key.
        sub_private_key: The sub agent's private key for re-signing.
        exec_act: The action actually performed (must match a cap[].action).
        pred: Predecessor task jti values (DAG dependencies). Empty list for root tasks.
        exec_ts: Execution timestamp (defaults to current time).
        status: Execution status: "completed", "failed", or "partial".
        inp_hash: Base64url SHA-256 hash of input data (optional).
        out_hash: Base64url SHA-256 hash of output data (optional).
        err: Error details when status is "failed" or "partial".

    Returns:
        Tuple of (ACTRecord, JWS compact serialization string).

    Raises:
        ACTPhaseError: If the mandate is already a Phase 2 token.
        ACTCapabilityError: If exec_act does not match any cap[].action.
        ACTValidationError: If the resulting record fails validation.
    """
    if mandate.is_phase2():
        raise ACTPhaseError("Cannot transition: token is already Phase 2")

    # Verify exec_act matches a capability
    cap_actions = {c.action for c in mandate.cap}
    if exec_act not in cap_actions:
        raise ACTCapabilityError(
            f"exec_act {exec_act!r} does not match any cap[].action: "
            f"{sorted(cap_actions)}"
        )

    record = ACTRecord.from_mandate(
        mandate,
        kid=sub_kid,
        exec_act=exec_act,
        pred=pred if pred is not None else [],
        exec_ts=exec_ts if exec_ts is not None else int(time.time()),
        status=status,
        inp_hash=inp_hash,
        out_hash=out_hash,
        err=err,
    )

    record.validate()

    # Re-sign with sub's private key
    signature = crypto_sign(sub_private_key, record.signing_input())
    compact = encode_jws(record, signature)

    return record, compact
