import os
from typing import Optional

from actions_logging.app_logging import logger
from common.common import raise_with_context
from github.env import exit_on_error_and_write_summary
from slack_sdk.errors import SlackApiError
from slack_wrapper.users import get_slack_user_by_email
from slack_wrapper.webclient import get_slack_web_client


def send_message_on_slack(recipient: str, text: str, markdown_text: Optional[str] = None) -> bool:
    """
    Send a message to a Slack user.

    :param recipient: The Slack recipient. Can be user ID (e.g. `U0870L7QZGC`),
                      channel name (e.g. `#devops-rnd`) or channel ID (e.g. `C02D0FGR5GF`).
    :param text: The text content of the message. If markdown_text is provided, this will be used as a fallback summary.
    :param markdown_text: The markdown content of the message.
    :return: True if the message was sent successfully, otherwise False.
    """
    try:
        slack_web_client = get_slack_web_client()

        blocks = [{"type": "section", "text": {"type": "mrkdwn", "text": markdown_text}}] if markdown_text else None

        logger.info(f"Sending message to Slack recipient {recipient}. Text: {text}, Blocks: {blocks}")
        response = slack_web_client.chat_postMessage(channel=recipient, text=text, blocks=blocks)
        logger.debug(f"Slack API response: {response}")
        if response.get("ok"):
            logger.info(f"Message sent to Slack recipient {recipient} successfully.")
            logger.debug(f"Slack SDK response: {response}")
            return True
        logger.error(f"Message not sent to Slack recipient {recipient}. Response: {response}")
        return False
    except SlackApiError as e:
        raise_with_context(e, SlackApiError, f"Error sending message to Slack recipient {recipient}")


def find_slack_user_by_email_and_send_message(
    email_address: str,
    text: str,
    markdown_text: Optional[str] = None,
) -> bool:
    """
    Finds a slack user by email address and sends a message to the user found.

    One of the parameters text or markdown_text must be provided as the message contents. If both are provided,
    the function will prefer the text parameter. If neither is provided, the function will raise an exception.

    :param email_address: The email address to find the Slack user by.
    :param text: The text content of the message. If markdown_text is provided, this will be used as a fallback summary.
    :param markdown_text: The markdown content of the message.
    :return: True if the message was sent successfully, otherwise False.
    """

    try:
        if not email_address:
            raise_with_context(
                None,
                ValueError,
                "email_address must be provided",
            )
        if not text and not markdown_text:
            raise_with_context(
                None,
                ValueError,
                "One of text or markdown_text must be provided",
            )

        logger.debug(f"Looking up slack user by email {email_address}")
        slack_user = get_slack_user_by_email(email_address)
        if not slack_user:
            raise_with_context(None, RuntimeError, f"Slack user not found for email address {email_address}")

        slack_user_id = slack_user.get("id")
        if not slack_user_id:
            raise_with_context(None, RuntimeError, f"Slack user ID not found for email address {email_address}")

        logger.debug(f"Slack user ID: {slack_user_id}")
        logger.debug(f"Slack message text: {text}")
        logger.debug(f"Slack message markdown text: {markdown_text}")

        return send_message_on_slack(user_id=slack_user_id, text=text, markdown_text=markdown_text)
    except Exception as e:
        raise_with_context(
            e,
            RuntimeError,
            f"Failed to send direct message to with email {email_address}",
        )
        return False


def main():
    try:
        slack_user_id = os.getenv("SLACK_USER_ID")
        email_address = os.getenv("SLACK_USER_EMAIL")
        slack_message_text = os.getenv("SLACK_MESSAGE_TEXT")
        slack_message_markdown_text = os.getenv("SLACK_MESSAGE_MARKDOWN_TEXT")

        if slack_user_id:
            send_message_on_slack(
                recipient=slack_user_id,
                text=slack_message_text,
                markdown_text=slack_message_markdown_text,
            )
        else:
            find_slack_user_by_email_and_send_message(
                email_address=email_address,
                text=slack_message_text,
                markdown_text=slack_message_markdown_text,
            )
    except Exception as e:
        exit_on_error_and_write_summary(f"Failed to send slack message: {e}")


if __name__ == "__main__":
    main()
