"""Consent state management for AI agent interactions.

Tracks per-user consent: what processing they've agreed to, when,
and through what mechanism. Supports consent withdrawal and full
export for data subject requests.
"""

import json
import time
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Optional


@dataclass
class ConsentRecord:
    """A single consent event."""
    user_id: str
    purpose: str
    action: str  # "grant", "withdraw"
    method: str  # "explicit", "implicit", "opt_in", "opt_out"
    timestamp: float
    metadata: dict


class ConsentManager:
    """Manage consent state per user.

    Usage:
        consent = ConsentManager("./consent.jsonl")

        # Record consent
        consent.grant("user_123", "customer_support", method="explicit")

        # Check before processing
        if consent.check("user_123", "customer_support"):
            # proceed with processing
            ...

        # User withdraws consent
        consent.withdraw("user_123", "customer_support")

        # Export for data subject request
        history = consent.export("user_123")
    """

    def __init__(self, path: str = "./agent_shield_consent.jsonl"):
        self.path = Path(path)

    def _append(self, record: ConsentRecord) -> None:
        self.path.parent.mkdir(parents=True, exist_ok=True)
        with open(self.path, "a") as f:
            f.write(json.dumps(asdict(record), default=str) + "\n")

    def _load_user_records(self, user_id: str) -> list[ConsentRecord]:
        if not self.path.exists():
            return []

        records = []
        with open(self.path, "r") as f:
            for line in f:
                line = line.strip()
                if not line:
                    continue
                try:
                    data = json.loads(line)
                    if data.get("user_id") == user_id:
                        records.append(ConsentRecord(**data))
                except (json.JSONDecodeError, TypeError):
                    continue
        return records

    def grant(
        self,
        user_id: str,
        purpose: str,
        method: str = "explicit",
        metadata: Optional[dict] = None,
    ) -> ConsentRecord:
        """Record that a user has granted consent for a purpose."""
        record = ConsentRecord(
            user_id=user_id,
            purpose=purpose,
            action="grant",
            method=method,
            timestamp=time.time(),
            metadata=metadata or {},
        )
        self._append(record)
        return record

    def withdraw(
        self,
        user_id: str,
        purpose: str,
        metadata: Optional[dict] = None,
    ) -> ConsentRecord:
        """Record that a user has withdrawn consent for a purpose."""
        record = ConsentRecord(
            user_id=user_id,
            purpose=purpose,
            action="withdraw",
            method="explicit",
            timestamp=time.time(),
            metadata=metadata or {},
        )
        self._append(record)
        return record

    def check(self, user_id: str, purpose: str) -> bool:
        """Check if a user currently has active consent for a purpose.

        Returns True if the most recent consent action for this
        user + purpose combination is a "grant".
        """
        records = self._load_user_records(user_id)
        # Find the most recent record for this purpose
        relevant = [r for r in records if r.purpose == purpose]
        if not relevant:
            return False
        latest = max(relevant, key=lambda r: r.timestamp)
        return latest.action == "grant"

    def active_consents(self, user_id: str) -> list[str]:
        """List all purposes with active consent for a user."""
        records = self._load_user_records(user_id)

        # Group by purpose, find latest action
        by_purpose: dict[str, ConsentRecord] = {}
        for r in records:
            if r.purpose not in by_purpose or r.timestamp > by_purpose[r.purpose].timestamp:
                by_purpose[r.purpose] = r

        return [
            purpose for purpose, record in by_purpose.items()
            if record.action == "grant"
        ]

    def export(self, user_id: str) -> list[dict]:
        """Export full consent history for a user (data subject request)."""
        records = self._load_user_records(user_id)
        return [asdict(r) for r in records]
