import json

from prefect.blocks.core import Block
from sentry_sdk import init, set_context, set_tag
from sentry_sdk.types import Event, Hint

from rana_process_sdk.domain import FormattedException, ProcessUserError

from .prefect_rana_runtime import PrefectRanaRuntime

__all__ = ["SentryBlock", "SENTRY_BLOCK_NAME"]

SENTRY_BLOCK_NAME = "sentry-block"
FAILED_STATE_MESSAGE = "Finished in state Failed"


def prefect_log_filter(event: Event, hint: Hint) -> Event | None:
    message = str((event.get("logentry") or {}).get("message"))
    if message.startswith("{"):
        try:
            # Exception with formatted messages have already been logged by sentry
            FormattedException(**json.loads(message))
        except Exception:
            return event
        else:
            return None
    if message.startswith(FAILED_STATE_MESSAGE) or ProcessUserError.__name__ in message:
        # Filter out exception from ending in failed state or user errors
        return None
    return event


class SentryBlock(Block):
    """Block that bootstraps Sentry with metadata related to Prefect flow runs."""

    dsn: str
    environment: str

    def init(self) -> None:
        """Initialize the sentry block."""
        prefect = PrefectRanaRuntime()

        try:
            init(
                self.dsn,
                environment=self.environment,
                # default_integrations=False,
                enable_tracing=False,
                auto_session_tracking=False,
                #  debug=True,
                before_send=prefect_log_filter,
            )

            set_tag("rana_process_id", str(prefect.process_id))
            set_tag("rana_job_id", str(prefect.job_id))
            set_context("rana_job_parameters", prefect.job_parameters)

        except Exception as e:
            prefect.logger.error("Failed to initialized Sentry. Inner exception: %s", e)
