from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Dict, Mapping, Optional, Union

from ..types import to_mapping


@dataclass
class VerifiableIntentRecord:
    recordId: str
    identity: Dict[str, Any]
    intent: Dict[str, Any]
    action: Dict[str, Any]
    outcome: Dict[str, Any]
    proof: Dict[str, Any]
    disclosure: Dict[str, Any]
    metadata: Dict[str, Any]


def aar_to_verifiable_intent(receipt: Union[Mapping[str, Any], Any]) -> Dict[str, Any]:
    r = to_mapping(receipt, "receipt")

    return {
        "recordId": r["receiptId"],
        "identity": {
            "id": r["principal"]["id"],
            "type": r["principal"]["type"],
        },
        "intent": {
            "description": "%s on %s" % (r["action"]["type"], r["action"]["target"]),
            "permissions": list(r["scope"]["permissions"]),
            "constraints": r["scope"].get("constraints"),
            "timestamp": r["timestamp"],
        },
        "action": {
            "agentId": r["agent"]["id"],
            "agentName": r["agent"].get("name"),
            "type": r["action"]["type"],
            "target": r["action"]["target"],
            "method": r["action"].get("method"),
            "status": r["action"]["status"],
            "timestamp": r["timestamp"],
        },
        "outcome": {
            "inputDigest": "%s:%s" % (r["inputHash"]["alg"], r["inputHash"]["digest"]),
            "outputDigest": "%s:%s" % (r["outputHash"]["alg"], r["outputHash"]["digest"]),
            "cost": {
                "amount": r["cost"]["amount"],
                "currency": r["cost"]["currency"],
            },
        },
        "proof": {
            "algorithm": r["signature"]["alg"],
            "keyId": r["signature"]["kid"],
            "publicKey": r["signature"].get("publicKey"),
            "signature": r["signature"]["sig"],
            "canonicalization": r["signature"]["canonicalization"],
        },
        "disclosure": {
            "mode": "minimal",
            "redactedFields": ["inputHash.raw", "outputHash.raw"],
        },
        "metadata": {**dict(r.get("metadata") or {}), "aarVersion": "1.0"},
    }


def verifiable_intent_to_aar(vi: Union[VerifiableIntentRecord, Mapping[str, Any]]) -> Dict[str, Any]:
    obj = vi.__dict__ if isinstance(vi, VerifiableIntentRecord) else dict(vi)

    outcome = obj.get("outcome") or {}
    input_digest_parts = str(outcome.get("inputDigest") or "").split(":", 1)
    output_digest_parts = str(outcome.get("outputDigest") or "").split(":", 1)

    input_alg = input_digest_parts[0] if len(input_digest_parts) > 0 and input_digest_parts[0] else "sha256"
    input_digest = input_digest_parts[1] if len(input_digest_parts) > 1 else ""

    output_alg = output_digest_parts[0] if len(output_digest_parts) > 0 and output_digest_parts[0] else "sha256"
    output_digest = output_digest_parts[1] if len(output_digest_parts) > 1 else ""

    action = obj.get("action") or {}
    identity = obj.get("identity") or {}
    intent = obj.get("intent") or {}
    proof = obj.get("proof") or {}

    raw_cost = outcome.get("cost")
    cost = (
        {
            "amount": raw_cost.get("amount"),
            "currency": raw_cost.get("currency"),
        }
        if isinstance(raw_cost, Mapping)
        else {"amount": "0", "currency": "USD"}
    )

    return {
        "receiptId": obj.get("recordId"),
        "agent": {
            "id": action.get("agentId"),
            "name": action.get("agentName"),
        },
        "principal": {
            "id": identity.get("id"),
            "type": identity.get("type"),
        },
        "action": {
            "type": action.get("type"),
            "target": action.get("target"),
            "method": action.get("method"),
            "status": action.get("status"),
        },
        "scope": {
            "permissions": list(intent.get("permissions") or []),
            "constraints": intent.get("constraints"),
        },
        "inputHash": {
            "alg": input_alg,
            "digest": input_digest,
        },
        "outputHash": {
            "alg": output_alg,
            "digest": output_digest,
        },
        "timestamp": action.get("timestamp"),
        "cost": cost,
        "signature": {
            "alg": proof.get("algorithm"),
            "kid": proof.get("keyId"),
            "publicKey": proof.get("publicKey"),
            "canonicalization": proof.get("canonicalization"),
            "sig": proof.get("signature"),
        },
        "metadata": {**dict(obj.get("metadata") or {}), "sourceFormat": "verifiable-intent"},
    }


aarToVerifiableIntent = aar_to_verifiable_intent
verifiableIntentToAAR = verifiable_intent_to_aar

__all__ = [
    "VerifiableIntentRecord",
    "aar_to_verifiable_intent",
    "aarToVerifiableIntent",
    "verifiable_intent_to_aar",
    "verifiableIntentToAAR",
]
