import json
import os

import requests
from actions_logging.app_logging import logger
from github.env import exit_on_error_and_write_summary, get_required_env_var, parse_bool_env_var
from slack_wrapper.constants import CANCELED, DANGER, GOOD, SLACK_WEBHOOK, UNDEFINED, WARNING

MAX_MESSAGE_SIZE = 2980


class SlackNotifier:
    github_server_url: str
    github_run_id: str
    github_repository: str
    github_event_name: str
    github_ref: str
    github_actor: str

    channel: str
    username: str
    title: str
    status: str
    token: str
    message: str

    def __init__(self):
        try:
            logger.info("Instantiating SlackNotifier")
            self.github_server_url = get_required_env_var("GITHUB_SERVER_URL")
            self.github_run_id = get_required_env_var("GITHUB_RUN_ID")
            self.github_repository = get_required_env_var("GITHUB_REPOSITORY")
            self.github_event_name = get_required_env_var("GITHUB_EVENT_NAME")
            self.github_ref = self.shorten_gh_ref(get_required_env_var("GITHUB_REF"))
            self.github_head_ref = os.getenv("GITHUB_HEAD_REF", "")
            self.github_actor = os.getenv("GITHUB_ACTOR").lower()
            self.channel = get_required_env_var("SLACK_CHANNEL").lower()
            self.username = get_required_env_var("SLACK_USERNAME")
            self.title = get_required_env_var("SLACK_TITLE")
            self.token = get_required_env_var("SLACK_TOKEN")
            self.message = get_required_env_var("SLACK_MESSAGE")
            if len(self.message) > MAX_MESSAGE_SIZE:
                self.message = self.message[:MAX_MESSAGE_SIZE] + "\n MESSAGE TRUNCATED"
                logger.info(f"slack message was too long truncated to {MAX_MESSAGE_SIZE} characters")
            self.status = os.getenv("SLACK_STATUS", "").lower()

            if self.github_head_ref:
                self.github_ref = self.github_head_ref
        except Exception as e:
            exit_on_error_and_write_summary(f"couldn't instantiate SlackNotify due to an error: {e}")

    def shorten_gh_ref(self, ref):
        return "/".join(ref.split("/")[2:])

    def _get_workflow_exec_url(self):
        return f"{self.github_server_url}/{self.github_repository}/actions/runs/{self.github_run_id}"

    def _get_commit(self):
        return f"{self.github_server_url}/{self.github_repository}/commit/{self.github_sha}"

    def build_title(self):
        status_emoji = UNDEFINED
        match self.status:
            case "good":
                status_emoji = GOOD
            case "cancelled":
                status_emoji = CANCELED
            case "warning":
                status_emoji = WARNING
            case "danger":
                status_emoji = DANGER
            case _:
                status_emoji = UNDEFINED

        text = " ".join([status_emoji, self.title, status_emoji])

        return {"type": "header", "text": {"type": "plain_text", "text": text, "emoji": True}}

    def build_payload(self):
        try:
            logger.info("Building payload for sending slack message.")
            title = self.build_title()
            message_body = self.build_message_body()

            blocks = [
                title,
                {"type": "divider"},
            ] + message_body

            payload = {
                "username": self.username,
                "channel": self.channel,
                "text": self.message,
                "icon_emoji": ":robot_face:",
                "blocks": blocks,
            }
            return payload
        except Exception as e:
            exit_on_error_and_write_summary(f"couldn't build slack notificaiton payload due to an error: {e}")

    def build_message_body(self):
        blocks = [
            {
                "type": "section",
                "fields": [
                    {
                        "type": "mrkdwn",
                        "text": f"`Git ref`: `{self.github_ref}`",
                    },
                    {
                        "type": "mrkdwn",
                        "text": f"`Github event`: `{self.github_event_name}`",
                    },
                    {
                        "type": "mrkdwn",
                        "text": f"`Triggered by`: `{self.github_actor}`",
                    },
                    {
                        "type": "mrkdwn",
                        "text": f"<{self._get_workflow_exec_url()}|Github Workflow execution>",
                    },
                ],
            },
            {"type": "divider"},
            {"type": "section", "text": {"type": "mrkdwn", "text": self.message}},
        ]
        return blocks

    def send_message(self, payload):
        try:
            url = f"{SLACK_WEBHOOK}/{self.token}"
            logger.debug(f"slack data: {payload}")
            tls_verify = parse_bool_env_var(os.getenv("TLS_VERIFY", True))
            response = requests.post(url, data=json.dumps(payload), verify=tls_verify)

            response.raise_for_status()
            if response.status_code < 300 and response.text == "ok":
                logger.info(f"slack returned {response.status_code} status code")
                logger.info_blue(f"response is {response.text}")
                return True
            else:
                logger.error(
                    f"sending slack message to {self.channel} failed. return {response.status_code} with {response.text}"
                )
                return False
        except Exception as e:
            exit_on_error_and_write_summary(f"an error occured while trying to send slack message: {e}")


def main():
    slack = SlackNotifier()
    payload = slack.build_payload()
    slack.send_message(payload)


if __name__ == "__main__":
    main()
