import time
from datetime import datetime

from core.buddy_service import BuddyService
from core.chat_blob import ChatBlob
from core.command_param_types import Options, Int, Any, Character, Const
from core.db import DB
from core.decorators import instance, event, command
from core.dict_object import DictObject
from core.job_scheduler import JobScheduler
from core.logger import Logger
from core.text import Text
from core.igncore import IgnCore
from modules.core.accounting.services.account_service import AccountService
from modules.core.ban.ban_service import BanService


@instance()
class MailController:

    def inject(self, registry):
        self.logger = Logger(__name__)
        self.bot: IgnCore = registry.get_instance("bot")
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.ban: BanService = registry.get_instance("ban_service")
        self.buddy_service: BuddyService = registry.get_instance("buddy_service")
        self.job_schedule: JobScheduler = registry.get_instance("job_scheduler")
        self.account_service: AccountService = registry.get_instance("account_service")

    def pre_start(self):
        self.db.exec(
            "CREATE TABLE IF NOT EXISTS mail("
            "id int primary key auto_increment, "
            "text text, "
            "recipient int not null, "
            "sender int not null, "
            "sent_at int not null, "
            "`read` int not null default 0)")

    @event(event_type="connect", description="register players with pending mails")
    def connect_event(self, _, _1):
        data = self.db.query(
            "SELECT a.char_id from mail m "
            "left join account a ON a.main = m.recipient "
            "WHERE  `read` = 0 and (a.disabled = 0 and a.member!=-1) "
            "group by a.char_id")
        for row in data:
            self.buddy_service.add_buddy(row.char_id, "mail")

    @event(event_type="member_logon", description="Send mails on logon")
    def logon_event(self, _, data):
        if not self.bot.is_ready():
            return
        if not self.account_service.simple_checks(data.account):
            return
        if "mail" in self.buddy_service.get_buddy(data.packet.char_id)["types"]:
            self.job_schedule.delayed_job(self.send_mail, 16, data.packet.char_id, self.get_mails(data.packet.char_id))

    def send_mail(self, _, sender, mail, greeting="Hey, you got some mails!"):
        if self.buddy_service.get_buddy(sender)["online"] == 0:
            return
        # hotfix for
        if len(mail) < 10:
            self.buddy_service.remove_buddy(sender, "mail")
            return
        self.bot.send_mass_message(sender, f"<red>{greeting}</red> <yellow>::</yellow> " +
                                   self.text.paginate_single(ChatBlob("Your mails", mail)))

    #####################
    #   Mail Management #
    #####################

    @command(command="mail", params=[Const('all', is_optional=True)], description="Show your mails",
             access_level="member")
    def mail_show(self, sender, const_all):
        mails, title = None, "You dont have any unread mails."

        if const_all:
            mails, title = self.get_mails(sender.sender.char_id, True), "All your recent Mails"
        else:
            mails, title = self.get_mails(sender.sender.char_id), "Your unread mails"
        if mails:
            self.bot.send_private_message(sender.sender.char_id, ChatBlob(title, mails))
        else:
            return title

    @command(command="mail", params=[Options(["read"]), Int("ID")],
             description="mark a mail as read", access_level="member")
    def mail_read(self, sender, _, mail_id):
        row = self.db.exec(
            "UPDATE mail set `read` = 1 where recipient=(SELECT main from account where char_id=? LIMIT 1) and id=?",
            [sender.sender.char_id, mail_id])
        if len(self.get_mails(sender.sender.char_id)) < 10:
            alts = self.account_service.get_alts(sender.sender.char_id)
            for i in alts:
                self.buddy_service.remove_buddy(i.char_id, "mail")
        if row == 0:
            return f"You dont have an unread mail with the ID <highlight>{mail_id}</highlight>."
        elif row == 1:
            return f"The mail with the ID <highlight>{mail_id}</highlight> has been marked as read."
        else:
            return "Something went wrong. please contact an administrator."

    @command(command="mail", params=[Options(["delete"]), Int("ID")],
             description="mark a mail as read", access_level="member")
    def mail_delete(self, sender, _, mail_id):
        row = self.db.exec(
            "DELETE FROM mail where recipient=(SELECT main from account where char_id=? LIMIT 1) and id=?",
            [sender.sender.char_id, mail_id])
        if len(self.get_mails(sender.sender.char_id)) < 10:
            alts = self.account_service.get_alts(sender.sender.char_id)
            for i in alts:
                self.buddy_service.remove_buddy(i.char_id, "mail")
        if row == 0:
            return f"You dont have a mail with the ID <highlight>{mail_id}</highlight>."
        elif row == 1:
            return f"The mail with the ID <highlight>{mail_id}</highlight> has been deleted."
        else:
            return "Something went wrong. please contact an administrator."

    @command(command="mail", params=[Options(["send"]), Character("recipient"), Any("text")],
             description="Send a mail to someone", access_level="member")
    def mail_send(self, sender, _, receiver, message):
        if not receiver.char_id:
            return f"Character <highlight>{receiver.name}</highlight> not found."
        recipient = self.account_service.get_account(receiver.char_id)
        if not recipient:
            return f"No account for <highlight>{receiver.name}</highlight> found."

        # if recipient.member == -1 or recipient.disabled == 1:
        if not self.account_service.simple_checks(recipient):
                return f"The Character <highlight>{recipient.name}</highlight> has " \
                   f"no active account in <highlight><myname></highlight>."
        self.db.exec("INSERT INTO mail(sender, recipient, text, sent_at) VALUES(?, ?, ?, ?)",
                     [sender.sender.char_id, recipient.main, message, time.time()])
        alts = self.account_service.get_alts(recipient.char_id)
        for i in alts:
            buddy = self.buddy_service.get_buddy(i.char_id) or []
            if "mail" not in buddy:
                if i.member == -1:
                    continue
                self.buddy_service.add_buddy(i.char_id, "mail")
            if self.buddy_service.is_online(i.char_id):
                self.send_mail(0, i.char_id, self.get_mails(i.char_id),
                               f"{sender.sender.name} just sent you a mail, please read it")
        return "Mail sent successfully."

    @command(command="mail", params=[Const("group"), Any("group"), Any("text")],
             description="Send a mail to a group of players", sub_command='sendgroup', access_level="moderator")
    def mail_send_group(self, sender, _, recipient, message):
        group = self.account_service.get_group_tag(recipient)
        users = []
        if group:
            # if group == "all":
            #     if sender.sender.access_level['level'] > 20:
            #         return "This group is unavailable."
            #     users = self.account_service.get_all_members()
            # else:
            users = self.account_service.get_by_group(group)

        elif not group:
            return f"Sorry, but the group <highlight>{recipient}</highlight> does not exist. " \
                   f"The following groups are defined: " \
                   f"<highlight>admin, council, [all - admin only group], moderator</highlight> " \
                   f"and <highlight>leaders</highlight>."

        count = 0
        readers = []
        if group != "all":
            message += f"<br><tab><header>» This mail has been sent to the " \
                       f"<highlight>{group}</highlight> group.</header>"
        else:
            message += f"<br><tab><header>» This mail has been sent to <highlight>everyone</highlight>.</header>"
        mails = []
        for user in users:
            if user.main == user.char_id:
                mails.append((sender.sender.char_id, user.main, message, time.time()))
                count += 1
            if user.online == 1:
                readers.append(DictObject({"name": user.name, "char_id": user.char_id}))
        with self.db.pool.get_connection() as conn:
            with conn.cursor() as cur:
                cur.executemany("INSERT INTO mail(sender, recipient, text, sent_at) VALUES(?, ?, ?, ?)", mails)
        for user in readers:
            self.send_mail(0, user.char_id, self.get_mails(user.char_id),
                           greeting=f"<highlight>{sender.sender.name}</highlight> just sent you a group mail, "
                                    f"please read it!")

        return f"I've sent the <highlight>{count}</highlight> mails to the group " \
               f"<highlight>{group}</highlight> for you. " \
               f"A total of <highlight>{len(readers)}</highlight> characters from this group are online, " \
               f"the have been notified."

    def get_single_mail(self, char_id, mail_id):
        return ChatBlob(f"Your Mail with the ID {mail_id}", self.format_mail(self.db.query_single(
            "SELECT * FROM mail where recipient=(SELECT main from account where char_id=?) and id = ?", [char_id, id])))

    def get_mails(self, char_id, all_mails=False):
        if all_mails:
            data = self.db.query(
                "SELECT * FROM mail where recipient=(SELECT main from account where char_id=?) order by id desc",
                [char_id])
        else:
            data = self.db.query(
                "SELECT * FROM mail where recipient=(SELECT main from account where char_id=?) and `read`=0 "
                "order by id desc",
                [char_id])
        blob = ""
        for row in data:
            blob += self.format_mail(row) + "<br>"
        return blob

    def format_mail(self, mail):
        # noinspection LongLine
        return \
            f"""
<notice>{self.bot.character_service.resolve_char_to_name(mail.sender) if mail.sender != 0 else "IGNCOM"}</notice> sent you a mail on <highlight>{datetime.utcfromtimestamp(mail.sent_at).strftime("%d.%m.%Y - %H:%M:%S")}</highlight>:
<white>{mail.text}</white>
 - <green>[{self.text.make_tellcmd('Mark as read', f'mail read {mail.id}')}] [{self.text.make_tellcmd('DELETE', f'mail delete {mail.id}')}]</green>
"""

    @event(event_type="main_changed", description="Fix mails")
    def fix_mails(self, _, data):
        self.db.exec("UPDATE mail set recipient=? where recipient=?", [data.new_main_id, data.old_main_id])
