"""Transactions resource — transaction monitoring and screening."""

from __future__ import annotations

import json
from dataclasses import asdict
from typing import Any, Dict, List, Optional, TYPE_CHECKING

if TYPE_CHECKING:
    from ..http_client import AsyncHttpClient, HttpClient

__all__ = ["Transactions", "AsyncTransactions"]


def _tx_body(params: Any) -> Dict[str, Any]:
    """Convert params to a JSON-safe dict, stripping None values."""
    body = asdict(params) if hasattr(params, "__dataclass_fields__") else params
    return {k: v for k, v in body.items() if v is not None}


class Transactions:
    """Transaction monitoring and screening (synchronous).

    Example::

        result = verilock.transactions.screen(
            ScreenTransactionParams(
                transaction_ref="TX-001",
                sender_name="Alice Corp",
                receiver_name="Bob Ltd",
                amount=15000,
                currency="USD",
            )
        )
        if result["risk_level"] == "high":
            print(f"{result['alerts_count']} alerts triggered")
    """

    def __init__(self, http: HttpClient) -> None:
        self._http = http

    def screen(
        self,
        params: Any,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Screen a single transaction for AML/CFT risk.

        Args:
            params: A :class:`~verilock.types.transactions.ScreenTransactionParams` or dict.

        Returns:
            Transaction screening result with risk level, score, and alerts.
        """
        return self._http.post(
            "/v1/transactions/screen", _tx_body(params), idempotency_key=idempotency_key
        )

    def screen_batch(
        self,
        params: Any,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Screen multiple transactions in a single batch request.

        Args:
            params: A :class:`~verilock.types.transactions.BatchScreenParams` or dict
                with a ``transactions`` list.

        Returns:
            Batch response with ``total`` and ``results`` list.
        """
        body = _tx_body(params)
        # Ensure nested transaction objects are also cleaned
        if "transactions" in body:
            body["transactions"] = [
                {k: v for k, v in tx.items() if v is not None}
                for tx in body["transactions"]
            ]
        return self._http.post(
            "/v1/transactions/screen/batch", body, idempotency_key=idempotency_key
        )

    def list(
        self,
        params: Optional[Any] = None,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """List transaction screenings with optional filters.

        Args:
            params: A :class:`~verilock.types.transactions.ListTransactionsParams` or dict.

        Returns:
            Paginated response with ``data`` and ``meta`` keys.
        """
        query: Optional[Dict[str, Any]] = None
        if params is not None:
            query = params.to_dict() if hasattr(params, "to_dict") else params
        return self._http.get("/v1/transactions", query, idempotency_key=idempotency_key)

    def retrieve(
        self,
        transaction_id: str,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Retrieve full details of a transaction screening.

        Args:
            transaction_id: The transaction screening ID.

        Returns:
            Full transaction detail with party info, alerts, and decision.
        """
        return self._http.get(
            f"/v1/transactions/{transaction_id}", idempotency_key=idempotency_key
        )

    def decide(
        self,
        transaction_id: str,
        params: Any,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Submit a decision (approve, reject, escalate) for a flagged transaction.

        Args:
            transaction_id: The transaction screening ID.
            params: A :class:`~verilock.types.transactions.TransactionDecisionParams` or dict.

        Returns:
            Decision confirmation with ``id``, ``status``, and ``decision``.
        """
        return self._http.post(
            f"/v1/transactions/{transaction_id}/decision",
            _tx_body(params),
            idempotency_key=idempotency_key,
        )

    def list_types(
        self,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """List available transaction types for classification.

        Returns:
            Response with a ``types`` list of transaction type objects.
        """
        return self._http.get("/v1/transactions/types", idempotency_key=idempotency_key)


class AsyncTransactions:
    """Transaction monitoring and screening (asynchronous)."""

    def __init__(self, http: AsyncHttpClient) -> None:
        self._http = http

    async def screen(
        self,
        params: Any,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Screen a single transaction for AML/CFT risk."""
        return await self._http.post(
            "/v1/transactions/screen", _tx_body(params), idempotency_key=idempotency_key
        )

    async def screen_batch(
        self,
        params: Any,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Screen multiple transactions in a single batch request."""
        body = _tx_body(params)
        if "transactions" in body:
            body["transactions"] = [
                {k: v for k, v in tx.items() if v is not None}
                for tx in body["transactions"]
            ]
        return await self._http.post(
            "/v1/transactions/screen/batch", body, idempotency_key=idempotency_key
        )

    async def list(
        self,
        params: Optional[Any] = None,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """List transaction screenings with optional filters."""
        query: Optional[Dict[str, Any]] = None
        if params is not None:
            query = params.to_dict() if hasattr(params, "to_dict") else params
        return await self._http.get("/v1/transactions", query, idempotency_key=idempotency_key)

    async def retrieve(
        self,
        transaction_id: str,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Retrieve full details of a transaction screening."""
        return await self._http.get(
            f"/v1/transactions/{transaction_id}", idempotency_key=idempotency_key
        )

    async def decide(
        self,
        transaction_id: str,
        params: Any,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """Submit a decision for a flagged transaction."""
        return await self._http.post(
            f"/v1/transactions/{transaction_id}/decision",
            _tx_body(params),
            idempotency_key=idempotency_key,
        )

    async def list_types(
        self,
        *,
        idempotency_key: Optional[str] = None,
    ) -> Dict[str, Any]:
        """List available transaction types for classification."""
        return await self._http.get(
            "/v1/transactions/types", idempotency_key=idempotency_key
        )
