from core.chat_blob import ChatBlob
from core.db import DB
from core.decorators import instance, event, setting
from core.dict_object import DictObject
from core.igncore import IgnCore
from core.logger import Logger
from core.public_channel_service import PublicChannelService
from core.setting_service import SettingService
from core.setting_types import BooleanSettingType
from core.text import Text
from core.util import Util
from modules.core.accounting.services.account_service import AccountService
from modules.orgbot.org.org_roster_controller import OrgRosterController
from modules.standard.online.online_display import OnlineDisplay


@instance()
class OrgChannelController:
    MESSAGE_SOURCE = "org_channel"
    ORG_CHANNEL_PREFIX = "[<cyan>Org</cyan>]"

    def __init__(self):
        self.logger = Logger(__name__)

    def inject(self, registry):
        self.bot: IgnCore = registry.get_instance("bot")
        self.db: DB = registry.get_instance("db")
        self.util: Util = registry.get_instance("util")
        self.character_service = registry.get_instance("character_service")
        self.message_hub_service = registry.get_instance("message_hub_service")
        self.setting_service: SettingService = registry.get_instance("setting_service")
        self.ban_service = registry.get_instance("ban_service")
        self.log_controller = registry.get_instance("log_controller", is_optional=True)
        self.online_controller = registry.get_instance("online_controller", is_optional=True)
        self.text: Text = registry.get_instance("text")
        self.account_service: AccountService = registry.get_instance("account_service")

    def pre_start(self):
        self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)

    def start(self):
        self.message_hub_service.register_message_destination(
                    self.MESSAGE_SOURCE, self.handle_incoming_relay_message,
                    ["private_channel", "websocket_relay", "cloak_reminder", "wave_counter", "shutdown_notice"],
                    [self.MESSAGE_SOURCE])

    def handle_incoming_relay_message(self, ctx):
        # {'source': 'org_channel', 'sender': {'char_id': 384018, 'name': 'Risianna'}, 'message': 'Sooo', 'formatted_message': "[<cyan>Org</cyan>] <a  href='user://Risianna'>Risianna</a>: Sooo"}
        if self.display_main().get_value() and ctx.source == "private_channel" and ctx.sender:
            name = f"[<cyan>Priv</cyan>] <yellow>{ctx.sender.name}</yellow>"
            if account := self.account_service.get_account(ctx.sender.char_id):
                if account.main != ctx.sender.char_id:
                    name += f" (<yellow>{account.name}</yellow>)"
            self.bot.send_org_message(name + ": " + ctx.message, fire_outgoing_event=False)
        else:
            self.bot.send_org_message(ctx.formatted_message, fire_outgoing_event=False)

    @event(event_type=PublicChannelService.ORG_CHANNEL_MESSAGE_EVENT,
           description="Relay messages from the org channel to the relay hub",
           is_hidden=True)
    def handle_org_message_event(self, _, event_data):
        if event_data.char_id == self.bot.get_char_id() or self.ban_service.get_ban(event_data.char_id):
            return

        if event_data.extended_message:
            message = event_data.extended_message.get_message()
        else:
            message = event_data.message

        if event_data.char_id == 4294967295 or event_data.char_id == 0:
            sender = None
            formatted_message = "{org} {msg}".format(org=self.ORG_CHANNEL_PREFIX,
                                                     msg=message)
        else:
            char_name = self.character_service.resolve_char_to_name(event_data.char_id)
            sender = DictObject({"char_id": event_data.char_id, "name": char_name})
            formatted_message = "{org} {char}: {msg}".format(org=self.ORG_CHANNEL_PREFIX,
                                                             char=self.text.make_charlink(char_name),
                                                             msg=message)

        self.message_hub_service.send_message(self.MESSAGE_SOURCE, sender, message, formatted_message)

    @event(event_type=OrgRosterController.ORG_MEMBER_LOGON_EVENT, description="Notify when org member logs on")
    def org_member_logon_event(self, _, event_data):
        if not self.bot.is_ready():
            return
        main = self.account_service.get_account(event_data.char_info.char_id)
        alt = f":: Alt of <highlight>{main.name}</highlight> " if event_data.account else ""
        if main.char_id == event_data.char_info.char_id:
            alt = ""
        logon = f" :: <grey>{event_data.account.logon}<grey>" if event_data.account.logon else ""
        msg = f"{self.text.format_char_info(event_data.char_info)} {alt}:: logged <green>on</green>.{logon}"
        self.bot.send_org_message(msg, fire_outgoing_event=False)

        self.message_hub_service.send_message(self.MESSAGE_SOURCE, None, None, "[<cyan>Org</cyan>] " + msg)
        afk_list = []
        if self.online_controller:
            afk_list = self.online_controller.afk_list
        od = OnlineDisplay(self.text, self.util, self.db, afk_list)
        params = [self.bot.name, self.bot.get_char_id()]
        self.bot.send_mass_message(event_data.packet.char_id,
                                   od.format_blob(od.format_by_channel_main("and channel_id IN (1, 2) ", params)))

    @event(event_type=OrgRosterController.ORG_MEMBER_LOGOFF_EVENT, description="Notify when org member logs off")
    def org_member_logoff_event(self, _, event_data):
        if not self.bot.is_ready():
            return
        char_name = self.character_service.resolve_char_to_name(event_data.packet.char_id)
        logoff = f" :: <grey>{event_data.account.logoff}<grey>" if event_data.account.logoff else ""
        msg = f"{char_name} logged <red>off</red>.{logoff}"
        self.bot.send_org_message(msg, fire_outgoing_event=False)
        self.message_hub_service.send_message(self.MESSAGE_SOURCE, None, None, "[<cyan>Org</cyan>] " + msg)

    @event(event_type=IgnCore.OUTGOING_ORG_MESSAGE_EVENT,
           description="Relay commands from the org channel to the relay hub",
           is_hidden=True)
    def outgoing_org_message_event(self, _, event_data):
        if isinstance(event_data.message, ChatBlob):
            pages = self.text.paginate(event_data.message,
                                       self.setting_service.get("org_channel_max_page_length").get_value())
            if len(pages) < 4:
                for page in pages:
                    # message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=page)
                    event_data.message.page_prefix = self.ORG_CHANNEL_PREFIX
                    self.message_hub_service.send_message(self.MESSAGE_SOURCE,
                                                          None,
                                                          page,
                                                          event_data.message)
            else:
                # message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=event_data.message.title)
                event_data.message.page_prefix = self.ORG_CHANNEL_PREFIX
                self.message_hub_service.send_message(self.MESSAGE_SOURCE,
                                                      None,
                                                      event_data.message.title,
                                                      event_data.message)
        else:
            message = "{org} {message}".format(org=self.ORG_CHANNEL_PREFIX, message=event_data.message)
            self.message_hub_service.send_message(self.MESSAGE_SOURCE,
                                                  None,
                                                  event_data.message,
                                                  message)

    @setting(name="display_main", value="false", description="Should the main be displayed in relayed messages")
    def display_main(self) -> BooleanSettingType:
        return BooleanSettingType()
