"""
BloomOS Kernel - Syscall Receipt
================================

Tamper-evident receipt for every syscall invocation.

Schema: syscall_receipt:v1

Each syscall produces a receipt that:
1. Links input → output via SHA256
2. Records IT tokens spent
3. Provides cost breakdown (cpu_ms, io_bytes, ram_bytes)
4. Creates a tamper-evident hash chain
"""

from __future__ import annotations

import hashlib
import json
import time
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any, Dict, Optional


@dataclass
class SyscallReceipt:
    """
    Tamper-evident receipt for a kernel syscall invocation.

    This receipt proves:
    - What syscall was invoked (with schema hash)
    - What inputs were provided (input_hash)
    - What output was produced (output_hash)
    - How much it cost (IT tokens + breakdown)
    - Whether it succeeded or failed (status)

    The receipt_hash makes the entire receipt tamper-evident.
    """
    schema: str = "syscall_receipt:v1"

    # Identity
    syscall_id: str = ""              # "cdna.decode.v1"
    actor: str = ""                    # Who invoked (e.g., "bridge", "dispatcher")

    # Versioning (for reproducibility)
    schema_hash: str = ""              # Hash of input schema
    handler_hash: str = ""             # Hash of handler code
    router_version_hash: str = ""      # Registry version hash

    # Determinism proof
    input_hash: str = ""               # SHA256 of inputs
    output_hash: str = ""              # SHA256 of result

    # IT token accounting
    it_tokens_spent: float = 0.0
    it_tokens_pre_authorized: float = 0.0
    cost_breakdown: Dict[str, float] = field(default_factory=dict)  # {cpu_ms, io_bytes, ram_bytes}

    # Timing
    timestamp_utc: str = ""
    duration_ms: float = 0.0

    # Status
    status: str = "OK"                 # "OK" | "FAIL" | "EPERM" | "ERESOURCE"
    error_message: Optional[str] = None
    warnings: list = field(default_factory=list)

    # Tamper-evident hash
    receipt_hash: str = ""

    def __post_init__(self):
        """Initialize timestamp if not provided."""
        if not self.timestamp_utc:
            self.timestamp_utc = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
        if not self.cost_breakdown:
            self.cost_breakdown = {"cpu_ms": 0.0, "io_bytes": 0.0, "ram_bytes": 0.0}

    def compute_hash(self) -> str:
        """Compute deterministic hash of the receipt (excluding receipt_hash)."""
        canonical = self.to_dict()
        canonical.pop("receipt_hash", None)
        blob = json.dumps(canonical, sort_keys=True, separators=(",", ":")).encode()
        return hashlib.sha256(blob).hexdigest()

    def finalize(self) -> "SyscallReceipt":
        """Finalize the receipt by computing the tamper-evident hash."""
        self.receipt_hash = self.compute_hash()
        return self

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dict for JSON serialization."""
        return {
            "schema": self.schema,
            "syscall_id": self.syscall_id,
            "actor": self.actor,
            "versioning": {
                "schema_hash": self.schema_hash,
                "handler_hash": self.handler_hash,
                "router_version_hash": self.router_version_hash,
            },
            "proof": {
                "input_hash": self.input_hash,
                "output_hash": self.output_hash,
            },
            "accounting": {
                "it_tokens_spent": round(self.it_tokens_spent, 6),
                "it_tokens_pre_authorized": round(self.it_tokens_pre_authorized, 6),
                "cost_breakdown": {
                    k: round(v, 6) for k, v in self.cost_breakdown.items()
                },
            },
            "timing": {
                "timestamp_utc": self.timestamp_utc,
                "duration_ms": round(self.duration_ms, 3),
            },
            "status": self.status,
            "error_message": self.error_message,
            "warnings": self.warnings,
            "receipt_hash": self.receipt_hash,
        }

    @classmethod
    def from_dict(cls, d: Dict[str, Any]) -> "SyscallReceipt":
        """Create from dict."""
        versioning = d.get("versioning", {})
        proof = d.get("proof", {})
        accounting = d.get("accounting", {})
        timing = d.get("timing", {})

        return cls(
            schema=d.get("schema", "syscall_receipt:v1"),
            syscall_id=d.get("syscall_id", ""),
            actor=d.get("actor", ""),
            schema_hash=versioning.get("schema_hash", ""),
            handler_hash=versioning.get("handler_hash", ""),
            router_version_hash=versioning.get("router_version_hash", ""),
            input_hash=proof.get("input_hash", ""),
            output_hash=proof.get("output_hash", ""),
            it_tokens_spent=accounting.get("it_tokens_spent", 0.0),
            it_tokens_pre_authorized=accounting.get("it_tokens_pre_authorized", 0.0),
            cost_breakdown=accounting.get("cost_breakdown", {}),
            timestamp_utc=timing.get("timestamp_utc", ""),
            duration_ms=timing.get("duration_ms", 0.0),
            status=d.get("status", "OK"),
            error_message=d.get("error_message"),
            warnings=d.get("warnings", []),
            receipt_hash=d.get("receipt_hash", ""),
        )

    def verify(self) -> bool:
        """Verify the receipt hash is valid (tamper-detection)."""
        expected = self.compute_hash()
        return expected == self.receipt_hash


def create_receipt(
    syscall_id: str,
    actor: str,
    *,
    input_hash: str = "",
    output_hash: str = "",
    status: str = "OK",
    duration_ms: float = 0.0,
    it_tokens_spent: float = 0.0,
    cost_breakdown: Optional[Dict[str, float]] = None,
    schema_hash: str = "",
    handler_hash: str = "",
    router_version_hash: str = "",
    error_message: Optional[str] = None,
    warnings: Optional[list] = None,
) -> SyscallReceipt:
    """
    Factory function to create a SyscallReceipt.

    Args:
        syscall_id: Canonical syscall name (e.g., "cdna.decode.v1")
        actor: Who invoked the syscall
        input_hash: SHA256 of inputs
        output_hash: SHA256 of result
        status: "OK" | "FAIL" | "EPERM" | "ERESOURCE"
        duration_ms: Execution time in milliseconds
        it_tokens_spent: IT tokens consumed
        cost_breakdown: {cpu_ms, io_bytes, ram_bytes}
        schema_hash: Hash of input schema
        handler_hash: Hash of handler code
        router_version_hash: Registry version hash
        error_message: Error message if status != "OK"
        warnings: List of warning messages

    Returns:
        Finalized SyscallReceipt
    """
    receipt = SyscallReceipt(
        syscall_id=syscall_id,
        actor=actor,
        input_hash=input_hash,
        output_hash=output_hash,
        status=status,
        duration_ms=duration_ms,
        it_tokens_spent=it_tokens_spent,
        cost_breakdown=cost_breakdown or {},
        schema_hash=schema_hash,
        handler_hash=handler_hash,
        router_version_hash=router_version_hash,
        error_message=error_message,
        warnings=warnings or [],
    )
    return receipt.finalize()
