import re

from core.command_param_types import Const, Options, Int, Any, Time
from core.db import DB
from core.decorators import command, instance, setting
from core.setting_types import TimeSettingType
from core.igncore import IgnCore
from modules.standard.loot.auction_strategy.auction_strategy import AuctionStrategy


@instance()
class AuctionController:
    def __init__(self):
        # noinspection PyTypeChecker
        self.auction: AuctionStrategy = None
        self.prepared = []

    def inject(self, registry):
        self.db: DB = registry.get_instance("db")
        self.bot: IgnCore = registry.get_instance("bot")

    def pre_start(self):
        self.db.shared.exec("CREATE TABLE IF NOT EXISTS auction_log ("
                            "auction_id INT PRIMARY KEY AUTO_INCREMENT, "
                            "item_ref VARCHAR(255) NOT NULL, "
                            "item_name VARCHAR(255) NOT NULL, "
                            "winner_id BIGINT NOT NULL, "
                            "auctioneer_id BIGINT NOT NULL, "
                            "time INT NOT NULL, "
                            "winning_bid INT NOT NULL, "
                            "second_highest_bid INT NOT NULL)")
        self.db.create_view("auction_log")

    @setting(name="auction_length", value="90s", description="Regular auction length in seconds")
    def auction_length(self):
        return TimeSettingType()

    @setting(name="auction_announce_interval", value="15s", description="Auction announce interval")
    def auction_announce_interval(self):
        return TimeSettingType()

    @command(command="auction", params=[], description="Show auction status",
             access_level="guest")
    def auction_cmd(self, _):
        if not self.is_auction_running():
            return "No auction running."

        return self.auction.get_auction_list()

    @command(command="auction",
             params=[Const("prepare"), Const("clear")],
             description="Clear the list of prepared items",
             access_level="moderator", sub_command="modify")
    def auction_prepare_clear(self, _, _1, _2):
        self.prepared = []
        return "The List has been cleared. Currently there are no prepared items."

    @command(command="auction",
             params=[Const("prepare"), Any("items")],
             description="Prepare items for an auction",
             access_level="moderator", sub_command="modify")
    def auction_prepare(self, _, _1, items):
        items = items.replace("&#39;", '"')
        items2 = re.findall(r"(([^<]+)?<a href=[\"\']itemref://(\d+)/(\d+)/(\d+)[\"\']>([^<]+)</a>([^<]+)?)", items)
        if items2:
            for item in items2:
                self.prepared.append(item)
        else:
            self.prepared.append(items)
        prep = ""
        for item in self.prepared:
            if prep == "":
                if isinstance(item, tuple):
                    prep = item[0]
                else:
                    prep = item
            else:
                if isinstance(item, tuple):
                    prep += ", " + item[0]
                else:
                    prep += ", " + item
        return "Currently prepared items: " + prep

    @command(command="auction",
             params=[Const("start"), Time("duration", is_optional=True)],
             description="Start an auction, with the items added by auction prepare",
             access_level="moderator", sub_command="modify")
    def auction_start_cmd(self, request, _, duration):
        if self.is_auction_running():
            return "Auction already running."
        if not self.prepared:
            return "You prepared no items"
        self.auction = AuctionStrategy()
        for item in self.prepared:
            if isinstance(item, tuple):
                self.auction.add_item(item[0])
            else:
                self.auction.add_item(item)
        self.prepared = []

        auction_length = duration or self.auction_length().get_value()
        announce_interval = self.auction_announce_interval().get_value()

        return self.auction.start(request.sender, auction_length, announce_interval)

    @command(command="auction", params=[Options(["cancel"])], description="Cancel ongoing auction",
             access_level="moderator", sub_command="modify")
    def auction_cancel_cmd(self, request, _):
        if not self.is_auction_running():
            return "No auction running."

        result = self.auction.cancel(request.sender)
        self.auction = None
        return result

    @command(command="auction", params=[Options(["end"])], description="end ongoing auction",
             access_level="moderator", sub_command="modify")
    def auction_cancel_cmd(self, request, _):
        if not self.is_auction_running():
            return "No auction running."

        result = self.auction.cancel(request.sender)
        self.auction = None
        return result

    @command(command="auction", params=[Const("bid"),
                                        Int("amount", is_optional=True),
                                        Const("all", is_optional=True),
                                        Int("item_index", is_optional=True)],
             description="Bid on an item", access_level="guest")
    def auction_bid_cmd(self, request, _, amount, all_amount, item_index):
        if not self.is_auction_running():
            return "No auction running."

        self.bot.send_mass_message(request.sender.char_id,
                                   self.auction.add_bid(request.sender, all_amount or amount, item_index, request))

    def is_auction_running(self):
        return self.auction and self.auction.is_running
