import os
import pickle
import typing as t
from enum import Enum
from logging import getLogger

from incident_response_slackbot.config import load_config, get_config
from incident_response_slackbot.db.database import Database
from incident_response_slackbot.openai_utils import (
    create_greeting,
    generate_awareness_question,
    get_thread_summary,
    get_user_awareness,
    messages_to_string,
)
from openai_slackbot.handlers import BaseActionHandler, BaseMessageHandler

logger = getLogger(__name__)

DATABASE = Database()

class InboundDirectMessageHandler(BaseMessageHandler):
    """
    Handles Direct Messages for incident response use cases
    """

    def __init__(self, slack_client):
        super().__init__(slack_client)
        self.config = get_config()

    async def should_handle(self, args):
        return True

    async def handle(self, args):
        event = args.event
        user_id = event.get("user")

        if not DATABASE.user_exists(user_id):
            # If the user_id does not exist, they're not part of an active chat
            return

        message_ts = DATABASE.get_ts(user_id)
        await self.send_message_to_channel(event, message_ts)

        user_awareness = await get_user_awareness(event["text"])
        logger.info(f"User awareness decision: {user_awareness}")

        if user_awareness["has_answered"]:
            await self.handle_user_response(user_id, message_ts)
        else:
            await self.nudge_user(user_id, message_ts)

    async def send_message_to_channel(self, event, message_ts):
        # Send the received message to the monitoring channel
        await self._slack_client.post_message(
            channel=self.config.feed_channel_id,
            text=f"Received message from <@{event['user']}>:\n> {event['text']}",
            thread_ts=message_ts,
        )

    async def handle_user_response(self, user_id, message_ts):
        # User has answered the question
        messages = await self._slack_client.get_thread_messages(
            channel=self.config.feed_channel_id,
            thread_ts=message_ts,
        )

        # Send the end message to the user
        thank_you = "Thanks for your time!"
        await self._slack_client.post_message(
            channel=user_id,
            text=thank_you,
        )

        # Send message to the channel
        await self._slack_client.post_message(
            channel=self.config.feed_channel_id,
            text=f"Sent message to <@{user_id}>:\n> {thank_you}",
            thread_ts=message_ts,
        )

        summary = await get_thread_summary(messages)

        # Send message to the channel
        await self._slack_client.post_message(
            channel=self.config.feed_channel_id,
            text=f"Here is the summary of the chat:\n> {summary}",
            thread_ts=message_ts,
        )

        DATABASE.delete(user_id)

        await self.end_chat(message_ts)

    async def end_chat(self, message_ts):
        original_blocks = await self._slack_client.get_original_blocks(
            message_ts, self.config.feed_channel_id
        )

        # Remove action buttons and add "Chat has ended" text
        new_blocks = [block for block in original_blocks if block.get("type") != "actions"]

        # Add the "Chat has ended" text
        new_blocks.append(
            {
                "type": "section",
                "block_id": "end_chat_automatically",
                "text": {
                    "type": "mrkdwn",
                    "text": f"The chat was automatically ended from SecurityBot review. :done_:",
                    "verbatim": True,
                },
            }
        )

        await self._slack_client.update_message(
            channel=self.config.feed_channel_id,
            blocks=new_blocks,
            ts=message_ts,
            text="Ended chat automatically",
        )

    async def nudge_user(self, user_id, message_ts):
        # User has not answered the question

        nudge_message = await generate_awareness_question()
        # Send the greeting message to the user
        await self._slack_client.post_message(
            channel=user_id,
            text=nudge_message,
        )

        # Send message to the channel
        await self._slack_client.post_message(
            channel=self.config.feed_channel_id,
            text=f"Sent message to <@{user_id}>:\n> {nudge_message}",
            thread_ts=message_ts,
        )


class InboundIncidentStartChatHandler(BaseActionHandler):
    def __init__(self, slack_client):
        super().__init__(slack_client)
        self.config = get_config()

    @property
    def action_id(self):
        return "start_chat_submit_action"

    async def handle(self, args):
        body = args.body
        original_message = body["container"]
        original_message_ts = original_message["message_ts"]
        alert_user_id = DATABASE.get_user_id(original_message_ts)
        user = body["user"]

        name = user["name"]
        first_name = name.split(".")[1]

        logger.info(f"Handling inbound incident start chat action from {user['name']}")

        # Update the blocks and elements
        blocks = self.update_blocks(body, alert_user_id)

        # Add the "Started a chat" text
        blocks.append(self.create_chat_start_section(user["id"]))

        messages = await self._slack_client.get_thread_messages(
            channel=self.config.feed_channel_id,
            thread_ts=original_message_ts,
        )

        message = await self._slack_client.update_message(
            channel=self.config.feed_channel_id,
            blocks=blocks,
            ts=original_message_ts,
            text=messages[0]["text"],
        )

        text_messages = messages_to_string(messages)
        logger.info(f"Alert and detail: {text_messages}")

        username = await self._slack_client.get_user_display_name(alert_user_id)

        greeting_message = await create_greeting(first_name, text_messages)
        logger.info(f"generated greeting message: {greeting_message}")

        # Send the greeting message to the user and to the channel
        await self.send_greeting_message(alert_user_id, greeting_message, original_message_ts)

        logger.info(f"Succesfully started chat with user: {username}")

        return message

    def update_blocks(self, body, alert_user_id):
        body_copy = body.copy()
        new_elements = []
        for block in body_copy.get("message", {}).get("blocks", []):
            if block.get("type") == "actions":
                for element in block.get("elements", []):
                    if element.get("action_id") == "do_nothing_submit_action":
                        element["action_id"] = "end_chat_submit_action"
                        element["text"]["text"] = "End Chat"
                        element["value"] = alert_user_id
                    new_elements.append(element)
                block["elements"] = new_elements
        return body_copy.get("message", {}).get("blocks", [])

    def create_chat_start_section(self, user_id):
        return {
            "type": "section",
            "block_id": "started_chat",
            "text": {
                "type": "mrkdwn",
                "text": f"<@{user_id}> started a chat.",
                "verbatim": True,
            },
        }

    async def send_greeting_message(self, alert_user_id, greeting_message, original_message_ts):
        # Send the greeting message to the user
        await self._slack_client.post_message(
            channel=alert_user_id,
            text=greeting_message,
        )

        # Send message to the channel
        await self._slack_client.post_message(
            channel=self.config.feed_channel_id,
            text=f"Sent message to <@{alert_user_id}>:\n> {greeting_message}",
            thread_ts=original_message_ts,
        )


class InboundIncidentDoNothingHandler(BaseActionHandler):
    """
    Handles incoming alerts and decides whether to take no action.
    This will close the alert and mark the status as complete.
    """

    def __init__(self, slack_client):
        super().__init__(slack_client)
        self.config = get_config()

    @property
    def action_id(self):
        return "do_nothing_submit_action"

    async def handle(self, args):
        body = args.body
        user_id = body["user"]["id"]
        original_message_ts = body["message"]["ts"]

        # Remove action buttons and add "Chat has ended" text
        new_blocks = [
            block
            for block in body.get("message", {}).get("blocks", [])
            if block.get("type") != "actions"
        ]

        # Add the "Chat has ended" text
        new_blocks.append(
            {
                "type": "section",
                "block_id": "do_nothing",
                "text": {
                    "type": "mrkdwn",
                    "text": f"<@{user_id}> decided that no action was necessary :done_:",
                    "verbatim": True,
                },
            }
        )

        await self._slack_client.update_message(
            channel=self.config.feed_channel_id,
            blocks=new_blocks,
            ts=original_message_ts,
            text="Do Nothing action selected",
        )


class InboundIncidentEndChatHandler(BaseActionHandler):
    """
    Ends the chat manually
    """

    def __init__(self, slack_client):
        super().__init__(slack_client)
        self.config = get_config()

    @property
    def action_id(self):
        return "end_chat_submit_action"

    async def handle(self, args):
        body = args.body
        user_id = body["user"]["id"]
        message_ts = body["message"]["ts"]

        alert_user_id = DATABASE.get_user_id(message_ts)

        original_blocks = await self._slack_client.get_original_blocks(
            message_ts, self.config.feed_channel_id
        )

        # Remove action buttons and add "Chat has ended" text
        new_blocks = [block for block in original_blocks if block.get("type") != "actions"]

        # Add the "Chat has ended" text
        new_blocks.append(
            {
                "type": "section",
                "block_id": "end_chat_manually",
                "text": {
                    "type": "mrkdwn",
                    "text": f"<@{user_id}> has ended the chat :done_:",
                    "verbatim": True,
                },
            }
        )

        await self._slack_client.update_message(
            channel=self.config.feed_channel_id,
            blocks=new_blocks,
            ts=message_ts,
            text="Ended chat automatically",
        )

        # User has answered the question
        messages = await self._slack_client.get_thread_messages(
            channel=self.config.feed_channel_id,
            thread_ts=message_ts,
        )

        thank_you = "Thanks for your time!"
        await self._slack_client.post_message(
            channel=alert_user_id,
            text=thank_you,
        )

        # Send message to the channel
        await self._slack_client.post_message(
            channel=self.config.feed_channel_id,
            text=f"Sent message to <@{alert_user_id}>:\n> {thank_you}",
            thread_ts=message_ts,
        )

        summary = await get_thread_summary(messages)

        # Send message to the channel
        await self._slack_client.post_message(
            channel=self.config.feed_channel_id,
            text=f"Here is the summary of the chat:\n> {summary}",
            thread_ts=message_ts,
        )

        DATABASE.delete(user_id)
