"""
EATP Trust Operations.

Implements the four core EATP operations:
- ESTABLISH: Create initial trust for an agent
- DELEGATE: Transfer trust from one agent to another
- VERIFY: Validate trust for an action
- AUDIT: Record agent actions

Phase 1 (Week 2) implements ESTABLISH and VERIFY.
Phase 1 (Week 3) implements DELEGATE and AUDIT.
"""

from dataclasses import dataclass, field
from datetime import datetime, timedelta
from enum import Enum
from typing import Any, Dict, List, Optional
from uuid import uuid4

from kaizen.trust.authority import (
    AuthorityPermission,
    OrganizationalAuthority,
    OrganizationalAuthorityRegistry,
)
from kaizen.trust.chain import (
    ActionResult,
    AuditAnchor,
    AuthorityType,
    CapabilityAttestation,
    CapabilityType,
    Constraint,
    ConstraintEnvelope,
    ConstraintType,
    DelegationRecord,
    GenesisRecord,
    TrustLineageChain,
    VerificationLevel,
    VerificationResult,
)
from kaizen.trust.crypto import (
    hash_chain,
    serialize_for_signing,
    sign,
    verify_signature,
)
from kaizen.trust.exceptions import (
    AgentAlreadyEstablishedError,
    AuthorityInactiveError,
    AuthorityNotFoundError,
    CapabilityNotFoundError,
    ConstraintViolationError,
    DelegationError,
    InvalidSignatureError,
    InvalidTrustChainError,
    TrustChainNotFoundError,
    TrustError,
    VerificationFailedError,
)
from kaizen.trust.store import PostgresTrustStore


@dataclass
class CapabilityRequest:
    """
    Request for a capability during ESTABLISH.

    Attributes:
        capability: Name of the capability (e.g., "analyze_data")
        capability_type: Type of capability (ACCESS, ACTION, etc.)
        constraints: Specific constraints for this capability
        scope: Optional scope restrictions (e.g., {"databases": ["finance_db"]})
    """

    capability: str
    capability_type: CapabilityType
    constraints: List[str] = field(default_factory=list)
    scope: Dict[str, Any] = field(default_factory=dict)


@dataclass
class ConstraintEvaluationResult:
    """Result of constraint evaluation."""

    permitted: bool
    violations: List[Dict[str, Any]] = field(default_factory=list)


class TrustKeyManager:
    """
    Manages cryptographic keys for trust operations.

    This is a simple in-memory implementation for Phase 1.
    Production would use HSM or secure key management service.
    """

    def __init__(self):
        """Initialize key manager."""
        self._keys: Dict[str, str] = {}  # key_id -> private_key

    def register_key(self, key_id: str, private_key: str) -> None:
        """
        Register a private key.

        Args:
            key_id: Identifier for the key
            private_key: Base64-encoded private key
        """
        self._keys[key_id] = private_key

    def get_key(self, key_id: str) -> Optional[str]:
        """
        Get a private key by ID.

        Args:
            key_id: Identifier for the key

        Returns:
            The private key or None if not found
        """
        return self._keys.get(key_id)

    async def sign(self, payload: str, key_id: str) -> str:
        """
        Sign a payload with a specific key.

        Args:
            payload: Data to sign
            key_id: Key to use for signing

        Returns:
            Base64-encoded signature

        Raises:
            ValueError: If key not found
        """
        private_key = self._keys.get(key_id)
        if not private_key:
            raise ValueError(f"Key not found: {key_id}")
        return sign(payload, private_key)

    async def verify(self, payload: str, signature: str, public_key: str) -> bool:
        """
        Verify a signature.

        Args:
            payload: Original data
            signature: Signature to verify
            public_key: Public key for verification

        Returns:
            True if signature is valid
        """
        return verify_signature(payload, signature, public_key)


class TrustOperations:
    """
    Core EATP trust operations.

    Implements the four operations that manipulate and verify Trust Lineage Chains:
    - ESTABLISH: Create initial trust
    - DELEGATE: Transfer trust (Week 3)
    - VERIFY: Validate trust
    - AUDIT: Record actions (Week 3)

    Example:
        >>> # Initialize components
        >>> store = PostgresTrustStore()
        >>> registry = OrganizationalAuthorityRegistry()
        >>> key_manager = TrustKeyManager()
        >>>
        >>> # Create operations instance
        >>> trust_ops = TrustOperations(registry, key_manager, store)
        >>> await trust_ops.initialize()
        >>>
        >>> # Establish trust for an agent
        >>> chain = await trust_ops.establish(
        ...     agent_id="agent-001",
        ...     authority_id="org-acme",
        ...     capabilities=[
        ...         CapabilityRequest(
        ...             capability="analyze_data",
        ...             capability_type=CapabilityType.ACCESS,
        ...         )
        ...     ],
        ... )
        >>>
        >>> # Verify trust for an action
        >>> result = await trust_ops.verify(
        ...     agent_id="agent-001",
        ...     action="analyze_data",
        ... )
    """

    def __init__(
        self,
        authority_registry: OrganizationalAuthorityRegistry,
        key_manager: TrustKeyManager,
        trust_store: PostgresTrustStore,
    ):
        """
        Initialize TrustOperations.

        Args:
            authority_registry: Registry for organizational authorities
            key_manager: Manager for cryptographic keys
            trust_store: Storage for trust chains
        """
        self.authority_registry = authority_registry
        self.key_manager = key_manager
        self.trust_store = trust_store
        self._initialized = False

    async def initialize(self) -> None:
        """Initialize trust operations and dependencies."""
        if self._initialized:
            return
        await self.authority_registry.initialize()
        await self.trust_store.initialize()
        self._initialized = True

    # =========================================================================
    # ESTABLISH Operation
    # =========================================================================

    async def establish(
        self,
        agent_id: str,
        authority_id: str,
        capabilities: List[CapabilityRequest],
        constraints: Optional[List[str]] = None,
        metadata: Optional[Dict[str, Any]] = None,
        expires_at: Optional[datetime] = None,
    ) -> TrustLineageChain:
        """
        ESTABLISH: Create initial trust for an agent.

        This operation creates a new Trust Lineage Chain for an agent,
        establishing the genesis of trust from an organizational authority.

        Args:
            agent_id: Unique identifier for the agent
            authority_id: Authority granting trust
            capabilities: Requested capabilities
            constraints: Initial constraints (applied to all capabilities)
            metadata: Additional context
            expires_at: Optional expiration datetime

        Returns:
            TrustLineageChain: Complete trust chain for agent

        Raises:
            AuthorityNotFoundError: If authority doesn't exist
            AuthorityInactiveError: If authority is not active
            AgentAlreadyEstablishedError: If agent already has trust
            TrustStoreDatabaseError: If storage fails
        """
        constraints = constraints or []
        metadata = metadata or {}

        # 1. Validate authority exists and is active
        authority = await self._validate_authority(authority_id)

        # 2. Check authority has permission to create agents
        if not authority.has_permission(AuthorityPermission.CREATE_AGENTS):
            raise TrustError(
                f"Authority {authority_id} does not have permission to create agents"
            )

        # 3. Check agent doesn't already have a trust chain
        try:
            existing = await self.trust_store.get_chain(agent_id)
            if existing:
                raise AgentAlreadyEstablishedError(agent_id)
        except TrustChainNotFoundError:
            pass  # Expected - agent should not exist

        # 4. Create Genesis Record
        genesis = GenesisRecord(
            id=f"gen-{uuid4()}",
            agent_id=agent_id,
            authority_id=authority_id,
            authority_type=authority.authority_type,
            created_at=datetime.utcnow(),
            expires_at=expires_at,
            signature="",  # Will be signed below
            signature_algorithm="Ed25519",
            metadata=metadata,
        )

        # 5. Sign genesis record
        genesis_payload = serialize_for_signing(genesis.to_signing_payload())
        genesis.signature = await self.key_manager.sign(
            genesis_payload, authority.signing_key_id
        )

        # 6. Create Capability Attestations
        capability_attestations = []
        for cap_request in capabilities:
            attestation = await self._create_capability_attestation(
                cap_request=cap_request,
                authority=authority,
                global_constraints=constraints,
                expires_at=expires_at,
            )
            capability_attestations.append(attestation)

        # 7. Create initial Constraint Envelope
        constraint_envelope = self._compute_constraint_envelope(
            agent_id=agent_id,
            genesis=genesis,
            capabilities=capability_attestations,
            delegations=[],
        )

        # 8. Create Trust Lineage Chain
        chain = TrustLineageChain(
            genesis=genesis,
            capabilities=capability_attestations,
            delegations=[],
            constraint_envelope=constraint_envelope,
            audit_anchors=[],
        )

        # 9. Store chain
        await self.trust_store.store_chain(chain, expires_at)

        return chain

    async def _validate_authority(
        self,
        authority_id: str,
    ) -> OrganizationalAuthority:
        """
        Validate that an authority exists and is active.

        Args:
            authority_id: Authority to validate

        Returns:
            The OrganizationalAuthority

        Raises:
            AuthorityNotFoundError: If not found
            AuthorityInactiveError: If inactive
        """
        return await self.authority_registry.get_authority(authority_id)

    async def _create_capability_attestation(
        self,
        cap_request: CapabilityRequest,
        authority: OrganizationalAuthority,
        global_constraints: List[str],
        expires_at: Optional[datetime],
    ) -> CapabilityAttestation:
        """
        Create and sign a capability attestation.

        Args:
            cap_request: The capability request
            authority: The attesting authority
            global_constraints: Constraints applied to all capabilities
            expires_at: Optional expiration

        Returns:
            Signed CapabilityAttestation
        """
        # Combine capability-specific and global constraints
        all_constraints = cap_request.constraints + global_constraints

        attestation = CapabilityAttestation(
            id=f"cap-{uuid4()}",
            capability=cap_request.capability,
            capability_type=cap_request.capability_type,
            constraints=all_constraints,
            attester_id=authority.id,
            attested_at=datetime.utcnow(),
            expires_at=expires_at,
            signature="",
            scope=cap_request.scope,
        )

        # Sign attestation
        payload = serialize_for_signing(attestation.to_signing_payload())
        attestation.signature = await self.key_manager.sign(
            payload, authority.signing_key_id
        )

        return attestation

    def _compute_constraint_envelope(
        self,
        agent_id: str,
        genesis: GenesisRecord,
        capabilities: List[CapabilityAttestation],
        delegations: List[DelegationRecord],
    ) -> ConstraintEnvelope:
        """
        Compute the effective constraint envelope for an agent.

        The constraint envelope aggregates all constraints from:
        - Genesis record
        - Capability attestations
        - Delegation records (constraint tightening)

        Args:
            agent_id: The agent ID
            genesis: Genesis record
            capabilities: Capability attestations
            delegations: Delegation records

        Returns:
            ConstraintEnvelope with all effective constraints
        """
        constraints = []

        # Add genesis-level constraints
        for name in genesis.metadata.get("constraints", []):
            constraints.append(
                Constraint(
                    id=f"con-{uuid4()}",
                    constraint_type=ConstraintType.RESOURCE_LIMIT,  # Default type
                    value=name,
                    source="genesis",
                )
            )

        # Add capability-level constraints
        for cap in capabilities:
            for name in cap.constraints:
                constraints.append(
                    Constraint(
                        id=f"con-{uuid4()}",
                        constraint_type=ConstraintType.ACTION_RESTRICTION,
                        value=name,
                        source=f"capability:{cap.id}",
                    )
                )

        # Add delegation constraints (constraint tightening)
        for delegation in delegations:
            for name in delegation.constraint_subset:
                constraints.append(
                    Constraint(
                        id=f"con-{uuid4()}",
                        constraint_type=ConstraintType.DATA_SCOPE,
                        value=name,
                        source=f"delegation:{delegation.id}",
                    )
                )

        # Create envelope
        envelope = ConstraintEnvelope(
            id=f"env-{uuid4()}",
            agent_id=agent_id,
            active_constraints=constraints,
            computed_at=datetime.utcnow(),
            valid_until=genesis.expires_at,
            constraint_hash="",  # Will be computed by __post_init__
        )

        return envelope

    # =========================================================================
    # VERIFY Operation
    # =========================================================================

    async def verify(
        self,
        agent_id: str,
        action: str,
        resource: Optional[str] = None,
        level: VerificationLevel = VerificationLevel.STANDARD,
        context: Optional[Dict[str, Any]] = None,
    ) -> VerificationResult:
        """
        VERIFY: Check if agent has trust to perform action.

        This is the primary trust verification operation, called before
        every agent action to ensure trust requirements are met.

        Verification Levels:
        - QUICK (~1ms): Hash and expiration check only
        - STANDARD (~5ms): + Capability and constraint validation
        - FULL (~50ms): + Cryptographic signature verification

        Args:
            agent_id: Agent requesting to act
            action: Action to perform
            resource: Optional resource being accessed
            level: Verification thoroughness
            context: Additional context for constraint evaluation

        Returns:
            VerificationResult: Whether action is permitted

        Note:
            This operation is designed for high performance as it's
            called before every agent action.
        """
        context = context or {}

        # 1. Get agent's trust chain
        try:
            chain = await self.trust_store.get_chain(agent_id)
        except TrustChainNotFoundError:
            return VerificationResult(
                valid=False,
                reason="No trust chain found",
                level=level,
            )

        # QUICK level: Just check hash and expiration
        if level == VerificationLevel.QUICK:
            return await self._verify_quick(chain, level)

        # STANDARD level: Check capabilities and constraints
        capability = self._match_capability(chain, action)
        if not capability:
            return VerificationResult(
                valid=False,
                reason=f"No capability found for action '{action}'",
                level=level,
            )

        # Evaluate constraints
        constraint_result = self._evaluate_constraints(
            chain.constraint_envelope,
            action,
            resource,
            context,
        )

        if not constraint_result.permitted:
            return VerificationResult(
                valid=False,
                reason="Constraint violation",
                violations=constraint_result.violations,
                level=level,
            )

        # FULL level: Also verify all signatures
        if level == VerificationLevel.FULL:
            signature_result = await self._verify_signatures(chain)
            if not signature_result.valid:
                return signature_result

        return VerificationResult(
            valid=True,
            level=level,
            capability_used=capability.id,
            effective_constraints=chain.get_effective_constraints(
                capability.capability
            ),
        )

    async def _verify_quick(
        self,
        chain: TrustLineageChain,
        level: VerificationLevel,
    ) -> VerificationResult:
        """
        Perform quick verification (expiration check only).

        Args:
            chain: Trust chain to verify
            level: Verification level

        Returns:
            VerificationResult
        """
        if chain.is_expired():
            return VerificationResult(
                valid=False,
                reason="Trust chain expired",
                level=level,
            )

        return VerificationResult(
            valid=True,
            level=level,
        )

    def _match_capability(
        self,
        chain: TrustLineageChain,
        action: str,
    ) -> Optional[CapabilityAttestation]:
        """
        Match an action to a capability using multiple matching strategies.

        Matching strategies (in order):
        1. Direct match: action == capability name
        2. Hierarchical match: "read_users" matches "read_*"
        3. Semantic match: Future - using embeddings

        Args:
            chain: Trust chain to search
            action: Action to match

        Returns:
            Matching CapabilityAttestation or None
        """
        # Direct match
        for cap in chain.capabilities:
            if cap.capability == action:
                if not cap.is_expired():
                    return cap

        # Hierarchical match (wildcard patterns)
        for cap in chain.capabilities:
            if self._capability_matches_pattern(cap.capability, action):
                if not cap.is_expired():
                    return cap

        return None

    def _capability_matches_pattern(
        self,
        pattern: str,
        action: str,
    ) -> bool:
        """
        Check if action matches capability pattern.

        Supports wildcards:
        - "read_*" matches "read_users", "read_data"
        - "*_admin" matches "user_admin", "system_admin"
        - "*" matches everything

        Args:
            pattern: Capability pattern (may include *)
            action: Action to match

        Returns:
            True if action matches pattern
        """
        if pattern == "*":
            return True

        if "*" not in pattern:
            return pattern == action

        # Simple wildcard matching
        if pattern.endswith("*"):
            prefix = pattern[:-1]
            return action.startswith(prefix)

        if pattern.startswith("*"):
            suffix = pattern[1:]
            return action.endswith(suffix)

        # Middle wildcard (e.g., "read_*_data")
        parts = pattern.split("*")
        if len(parts) == 2:
            return action.startswith(parts[0]) and action.endswith(parts[1])

        return False

    def _evaluate_constraints(
        self,
        envelope: ConstraintEnvelope,
        action: str,
        resource: Optional[str],
        context: Dict[str, Any],
    ) -> ConstraintEvaluationResult:
        """
        Evaluate constraints for an action.

        Args:
            envelope: Constraint envelope
            action: Action being performed
            resource: Resource being accessed
            context: Additional context

        Returns:
            ConstraintEvaluationResult
        """
        violations = []

        # Check if envelope is valid
        if not envelope.is_valid():
            return ConstraintEvaluationResult(
                permitted=False,
                violations=[
                    {"constraint": "envelope", "reason": "Constraint envelope expired"}
                ],
            )

        # Evaluate each constraint
        for constraint in envelope.active_constraints:
            result = self._evaluate_single_constraint(
                constraint,
                action,
                resource,
                context,
            )
            if not result["permitted"]:
                violations.append(
                    {
                        "constraint_id": constraint.id,
                        "constraint_value": str(constraint.value),
                        "reason": result["reason"],
                    }
                )

        return ConstraintEvaluationResult(
            permitted=len(violations) == 0,
            violations=violations,
        )

    def _evaluate_single_constraint(
        self,
        constraint: Constraint,
        action: str,
        resource: Optional[str],
        context: Dict[str, Any],
    ) -> Dict[str, Any]:
        """
        Evaluate a single constraint.

        Built-in constraint evaluators:
        - time_window: Check if current time is within allowed window
        - rate_limit: Check if rate limit is exceeded
        - resource_access: Check if resource access is allowed
        - read_only: Ensure only read operations

        Args:
            constraint: Constraint to evaluate
            action: Action being performed
            resource: Resource being accessed
            context: Additional context

        Returns:
            Dict with 'permitted' bool and optional 'reason'
        """
        # Get constraint value as string for matching
        value = str(constraint.value).lower()

        # Time window constraint
        if value == "business_hours_only" or value.startswith("time_window"):
            current_time = context.get("current_time", datetime.utcnow())
            if isinstance(current_time, datetime):
                hour = current_time.hour
                if hour < 9 or hour >= 17:  # 9 AM to 5 PM
                    return {
                        "permitted": False,
                        "reason": f"Action not permitted outside business hours (current hour: {hour})",
                    }

        # Read-only constraint
        if value == "read_only":
            write_actions = ["write", "update", "delete", "create", "modify"]
            for wa in write_actions:
                if wa in action.lower():
                    return {
                        "permitted": False,
                        "reason": f"Write action '{action}' not permitted under read_only constraint",
                    }

        # Audit required (always passes, but logs)
        if value == "audit_required":
            # This constraint doesn't block, just requires audit
            pass

        # No PII export constraint
        if value == "no_pii_export":
            if "export" in action.lower() and context.get("contains_pii", False):
                return {
                    "permitted": False,
                    "reason": "Cannot export data containing PII",
                }

        # Default: permit if constraint not recognized
        return {"permitted": True}

    async def _verify_signatures(
        self,
        chain: TrustLineageChain,
    ) -> VerificationResult:
        """
        Verify all signatures in a trust chain.

        Args:
            chain: Trust chain to verify

        Returns:
            VerificationResult
        """
        # Verify genesis signature
        authority = await self.authority_registry.get_authority(
            chain.genesis.authority_id,
            include_inactive=True,  # Allow inactive for historical verification
        )

        genesis_payload = serialize_for_signing(chain.genesis.to_signing_payload())
        if not await self.key_manager.verify(
            genesis_payload,
            chain.genesis.signature,
            authority.public_key,
        ):
            return VerificationResult(
                valid=False,
                reason="Invalid genesis signature",
                level=VerificationLevel.FULL,
            )

        # Verify capability signatures
        for cap in chain.capabilities:
            cap_payload = serialize_for_signing(cap.to_signing_payload())
            if not await self.key_manager.verify(
                cap_payload,
                cap.signature,
                authority.public_key,
            ):
                return VerificationResult(
                    valid=False,
                    reason=f"Invalid capability signature: {cap.id}",
                    level=VerificationLevel.FULL,
                )

        # Verify delegation signatures (if any)
        for delegation in chain.delegations:
            # For delegations, we need the delegator's public key
            # This requires looking up the delegator's chain
            try:
                delegator_chain = await self.trust_store.get_chain(
                    delegation.delegator_id
                )
                # Use authority's key for now (simplified - production would use agent keys)
                del_payload = serialize_for_signing(delegation.to_signing_payload())
                # Note: In production, each agent would have their own key
                # For Phase 1, we skip delegation signature verification
            except TrustChainNotFoundError:
                return VerificationResult(
                    valid=False,
                    reason=f"Delegator chain not found: {delegation.delegator_id}",
                    level=VerificationLevel.FULL,
                )

        return VerificationResult(
            valid=True,
            level=VerificationLevel.FULL,
        )

    # =========================================================================
    # Helper methods for integration
    # =========================================================================

    async def get_agent_capabilities(
        self,
        agent_id: str,
    ) -> List[str]:
        """
        Get list of capability names for an agent.

        Args:
            agent_id: Agent to query

        Returns:
            List of capability names

        Raises:
            TrustChainNotFoundError: If agent has no trust chain
        """
        chain = await self.trust_store.get_chain(agent_id)
        return [cap.capability for cap in chain.capabilities if not cap.is_expired()]

    # =========================================================================
    # DELEGATE Operation
    # =========================================================================

    async def delegate(
        self,
        delegator_id: str,
        delegatee_id: str,
        task_id: str,
        capabilities: List[str],
        additional_constraints: Optional[List[str]] = None,
        expires_at: Optional[datetime] = None,
        metadata: Optional[Dict[str, Any]] = None,
    ) -> DelegationRecord:
        """
        DELEGATE: Transfer trust from one agent to another.

        Delegation enables agents to work together by allowing one agent
        (delegator) to temporarily grant a subset of its capabilities to
        another agent (delegatee) for a specific task.

        Key constraints:
        - Delegator can only delegate capabilities they possess
        - Delegatee's constraints can only be TIGHTER than delegator's
        - Delegations are time-limited and task-scoped
        - All delegations are cryptographically signed

        Args:
            delegator_id: Agent delegating trust
            delegatee_id: Agent receiving delegated trust
            task_id: Unique identifier for the delegated task
            capabilities: Capability names to delegate (subset of delegator's)
            additional_constraints: Additional constraints for delegatee
            expires_at: When delegation expires
            metadata: Additional context

        Returns:
            DelegationRecord: Signed delegation record

        Raises:
            TrustChainNotFoundError: If delegator has no trust chain
            CapabilityNotFoundError: If capability not in delegator's chain
            DelegationError: If delegation violates constraints
        """
        additional_constraints = additional_constraints or []
        metadata = metadata or {}

        # 1. Get delegator's trust chain
        try:
            delegator_chain = await self.trust_store.get_chain(delegator_id)
        except TrustChainNotFoundError:
            raise TrustChainNotFoundError(delegator_id)

        # 2. Verify delegator has all requested capabilities
        delegator_caps = {cap.capability for cap in delegator_chain.capabilities}
        for requested_cap in capabilities:
            # Use pattern matching for wildcard capabilities
            if not any(
                self._capability_matches_pattern(dc, requested_cap)
                for dc in delegator_caps
            ):
                raise CapabilityNotFoundError(
                    requested_cap,
                    f"Delegator {delegator_id} does not have capability '{requested_cap}'",
                )

        # 3. Verify delegator's trust is not expired
        if delegator_chain.is_expired():
            raise DelegationError(
                "Delegator's trust chain is expired",
                delegator_id=delegator_id,
                delegatee_id=delegatee_id,
            )

        # 4. Verify delegator can delegate (not explicitly restricted)
        delegator_constraints = [
            str(c.value).lower()
            for c in delegator_chain.constraint_envelope.active_constraints
        ]
        if "no_delegation" in delegator_constraints:
            raise DelegationError(
                "Delegator is restricted from delegating trust",
                delegator_id=delegator_id,
                delegatee_id=delegatee_id,
            )

        # 5. Build constraint subset (tightening only)
        # Start with delegator's constraints, add additional ones
        constraint_subset = list(delegator_constraints) + additional_constraints

        # 6. Calculate delegation expiry (can't exceed delegator's)
        if delegator_chain.genesis.expires_at:
            if expires_at is None:
                expires_at = delegator_chain.genesis.expires_at
            else:
                expires_at = min(expires_at, delegator_chain.genesis.expires_at)

        # 7. Create DelegationRecord
        delegation = DelegationRecord(
            id=f"del-{uuid4()}",
            delegator_id=delegator_id,
            delegatee_id=delegatee_id,
            task_id=task_id,
            capabilities_delegated=capabilities,
            constraint_subset=constraint_subset,
            delegated_at=datetime.utcnow(),
            expires_at=expires_at,
            signature="",  # Will be signed below
        )

        # 8. Sign the delegation record
        # Use the authority's key that established the delegator
        authority_id = delegator_chain.genesis.authority_id
        authority = await self.authority_registry.get_authority(authority_id)

        delegation_payload = serialize_for_signing(delegation.to_signing_payload())
        delegation.signature = await self.key_manager.sign(
            delegation_payload,
            authority.signing_key_id,
        )

        # 9. Get or create delegatee's trust chain
        try:
            delegatee_chain = await self.trust_store.get_chain(delegatee_id)
            # Add delegation to existing chain
            delegatee_chain.delegations.append(delegation)
            # Recompute constraint envelope
            delegatee_chain.constraint_envelope = self._compute_constraint_envelope(
                agent_id=delegatee_id,
                genesis=delegatee_chain.genesis,
                capabilities=delegatee_chain.capabilities,
                delegations=delegatee_chain.delegations,
            )
            await self.trust_store.update_chain(delegatee_chain)
        except TrustChainNotFoundError:
            # Create a derived chain for the delegatee
            # The delegatee inherits trust through delegation, not direct establishment
            derived_genesis = GenesisRecord(
                id=f"gen-{uuid4()}",
                agent_id=delegatee_id,
                authority_id=authority_id,
                authority_type=delegator_chain.genesis.authority_type,
                created_at=datetime.utcnow(),
                expires_at=expires_at,
                signature="",
                signature_algorithm="Ed25519",
                metadata={
                    "derived_from": delegator_id,
                    "delegation_id": delegation.id,
                },
            )

            # Sign derived genesis
            genesis_payload = serialize_for_signing(
                derived_genesis.to_signing_payload()
            )
            derived_genesis.signature = await self.key_manager.sign(
                genesis_payload,
                authority.signing_key_id,
            )

            # Create capability attestations for delegated capabilities
            derived_capabilities = []
            for cap_name in capabilities:
                # Find matching capability from delegator
                source_cap = next(
                    (
                        c
                        for c in delegator_chain.capabilities
                        if self._capability_matches_pattern(c.capability, cap_name)
                    ),
                    None,
                )
                if source_cap:
                    derived_cap = CapabilityAttestation(
                        id=f"cap-{uuid4()}",
                        capability=cap_name,
                        capability_type=source_cap.capability_type,
                        constraints=constraint_subset,
                        attester_id=authority_id,
                        attested_at=datetime.utcnow(),
                        expires_at=expires_at,
                        signature="",
                        scope=source_cap.scope,
                    )
                    cap_payload = serialize_for_signing(
                        derived_cap.to_signing_payload()
                    )
                    derived_cap.signature = await self.key_manager.sign(
                        cap_payload,
                        authority.signing_key_id,
                    )
                    derived_capabilities.append(derived_cap)

            # Compute constraint envelope
            constraint_envelope = self._compute_constraint_envelope(
                agent_id=delegatee_id,
                genesis=derived_genesis,
                capabilities=derived_capabilities,
                delegations=[delegation],
            )

            # Create and store the derived chain
            delegatee_chain = TrustLineageChain(
                genesis=derived_genesis,
                capabilities=derived_capabilities,
                delegations=[delegation],
                constraint_envelope=constraint_envelope,
                audit_anchors=[],
            )
            await self.trust_store.store_chain(delegatee_chain, expires_at)

        return delegation

    # =========================================================================
    # AUDIT Operation
    # =========================================================================

    async def audit(
        self,
        agent_id: str,
        action: str,
        resource: Optional[str] = None,
        result: ActionResult = ActionResult.SUCCESS,
        context: Optional[Dict[str, Any]] = None,
        parent_anchor_id: Optional[str] = None,
        audit_store: Optional[Any] = None,
    ) -> AuditAnchor:
        """
        AUDIT: Record an agent action in the audit trail.

        Every agent action that passes verification should be recorded
        in the audit trail for compliance and forensic analysis.

        Key features:
        - Append-only (immutable audit trail)
        - Cryptographically signed
        - Chain-linked via parent_anchor_id for causality
        - Includes trust chain hash for tamper detection

        Args:
            agent_id: Agent that performed the action
            action: Action that was performed
            resource: Resource that was accessed
            result: Outcome of the action
            context: Additional context (tool calls, inputs, etc.)
            parent_anchor_id: Link to parent action (for causal chains)
            audit_store: Optional audit store (uses default if not provided)

        Returns:
            AuditAnchor: The recorded audit anchor

        Raises:
            TrustChainNotFoundError: If agent has no trust chain
            AuditStoreError: If audit storage fails
        """
        context = context or {}

        # 1. Get agent's trust chain
        try:
            chain = await self.trust_store.get_chain(agent_id)
        except TrustChainNotFoundError:
            raise TrustChainNotFoundError(agent_id)

        # 2. Compute current trust chain hash
        trust_chain_hash = hash_chain(chain)

        # 3. Create audit anchor
        anchor = AuditAnchor(
            id=f"aud-{uuid4()}",
            agent_id=agent_id,
            action=action,
            resource=resource,
            timestamp=datetime.utcnow(),
            trust_chain_hash=trust_chain_hash,
            result=result,
            parent_anchor_id=parent_anchor_id,
            signature="",  # Will be signed below
            context=context,
        )

        # 4. Sign the audit anchor
        authority_id = chain.genesis.authority_id
        authority = await self.authority_registry.get_authority(authority_id)

        anchor_payload = serialize_for_signing(anchor.to_signing_payload())
        anchor.signature = await self.key_manager.sign(
            anchor_payload,
            authority.signing_key_id,
        )

        # 5. Store in audit store (if provided)
        if audit_store:
            await audit_store.append(anchor)

        # 6. Add to chain's audit anchors (in-memory)
        chain.audit_anchors.append(anchor)

        return anchor

    # =========================================================================
    # Helper methods for integration
    # =========================================================================

    async def get_agent_capabilities(
        self,
        agent_id: str,
    ) -> List[str]:
        """
        Get list of capability names for an agent.

        Args:
            agent_id: Agent to query

        Returns:
            List of capability names

        Raises:
            TrustChainNotFoundError: If agent has no trust chain
        """
        chain = await self.trust_store.get_chain(agent_id)
        return [cap.capability for cap in chain.capabilities if not cap.is_expired()]

    async def get_agent_constraints(
        self,
        agent_id: str,
    ) -> List[str]:
        """
        Get list of all constraint names for an agent.

        Args:
            agent_id: Agent to query

        Returns:
            List of constraint names

        Raises:
            TrustChainNotFoundError: If agent has no trust chain
        """
        chain = await self.trust_store.get_chain(agent_id)
        return [str(c.value) for c in chain.constraint_envelope.active_constraints]

    async def revoke_trust(
        self,
        agent_id: str,
        reason: Optional[str] = None,
    ) -> None:
        """
        Revoke trust for an agent (soft delete).

        Args:
            agent_id: Agent to revoke
            reason: Optional reason for revocation

        Raises:
            TrustChainNotFoundError: If agent has no trust chain
        """
        await self.trust_store.delete_chain(agent_id, soft_delete=True)

    async def get_delegation_chain(
        self,
        agent_id: str,
    ) -> List[DelegationRecord]:
        """
        Get all delegations for an agent.

        Args:
            agent_id: Agent to query

        Returns:
            List of DelegationRecords

        Raises:
            TrustChainNotFoundError: If agent has no trust chain
        """
        chain = await self.trust_store.get_chain(agent_id)
        return chain.delegations

    async def revoke_delegation(
        self,
        delegation_id: str,
        delegatee_id: str,
    ) -> None:
        """
        Revoke a specific delegation.

        Args:
            delegation_id: Delegation to revoke
            delegatee_id: Agent whose delegation to revoke

        Raises:
            TrustChainNotFoundError: If agent has no trust chain
            DelegationError: If delegation not found
        """
        chain = await self.trust_store.get_chain(delegatee_id)

        # Find and remove the delegation
        found = False
        for i, delegation in enumerate(chain.delegations):
            if delegation.id == delegation_id:
                chain.delegations.pop(i)
                found = True
                break

        if not found:
            raise DelegationError(
                f"Delegation {delegation_id} not found for agent {delegatee_id}",
                delegator_id="unknown",
                delegatee_id=delegatee_id,
            )

        # Recompute constraint envelope
        chain.constraint_envelope = self._compute_constraint_envelope(
            agent_id=delegatee_id,
            genesis=chain.genesis,
            capabilities=chain.capabilities,
            delegations=chain.delegations,
        )

        await self.trust_store.update_chain(chain)
