from src import utils

CAPABILITIES = [
    utils.irc.Capability("multi-prefix"),
    utils.irc.Capability("chghost"),
    utils.irc.Capability("invite-notify"),
    utils.irc.Capability("account-tag"),
    utils.irc.Capability("account-notify"),
    utils.irc.Capability("extended-join"),
    utils.irc.Capability("away-notify"),
    utils.irc.Capability("userhost-in-names"),
    utils.irc.Capability("message-tags", "draft/message-tags-0.2"),
    utils.irc.Capability("server-time"),
    utils.irc.Capability("cap-notify"),
    utils.irc.Capability("batch"),
    utils.irc.Capability("echo-message"),
    utils.irc.Capability(None, "draft/labeled-response"),
    utils.irc.Capability(None, "draft/rename"),
    utils.irc.Capability(None, "draft/setname")
]

def _match_caps(our_capabilities, offered_capabilities):
    matched = {}
    for capability in our_capabilities:
        available = capability.available(offered_capabilities)
        if available:
            matched[available] = capability
    return matched

def _caps_offered(server, caps):
    blacklist = server.get_setting("blacklisted-caps", [])
    for cap_name, cap in caps.items():
        if not cap_name in blacklist:
            server.capability_queue[cap_name] = cap

def cap(events, event):
    capabilities = utils.parse.keyvalue(event["args"][-1])
    subcommand = event["args"][1].lower()
    is_multiline = len(event["args"]) > 3 and event["args"][2] == "*"

    if subcommand == "ls":
        event["server"].cap_started = True
        event["server"].server_capabilities.update(capabilities)
        if not is_multiline:
            server_caps = list(event["server"].server_capabilities.keys())
            matched_caps = _match_caps(CAPABILITIES, server_caps)

            module_caps = events.on("received.cap.ls").call(
                capabilities=event["server"].server_capabilities,
                server=event["server"])
            module_caps = list(filter(None, module_caps))
            matched_caps.update(_match_caps(module_caps, server_caps))

            _caps_offered(event["server"], matched_caps)

            if event["server"].capability_queue:
                event["server"].send_capability_queue()
            else:
                event["server"].send_capability_end()
    elif subcommand == "new":
        capabilities_keys = capabilities.keys()
        event["server"].server_capabilities.update(capabilities)

        matched_caps = _match_caps(list(capabilities_keys))

        module_caps = events.on("received.cap.new").call(
            server=event["server"], capabilities=capabilities)
        module_caps = list(filter(None, module_caps))
        matched_caps.update(_match_caps(module_caps, capabilities_keys))

        _caps_offered(event["server"], matched_caps)

        if event["server"].capability_queue:
            event["server"].send_capability_queue()
    elif subcommand == "del":
        for capability in capabilities.keys():
            event["server"].agreed_capabilities.discard(capability)
            del event["server"].server_capabilities[capability]

        events.on("received.cap.del").call(server=event["server"],
            capabilities=capabilities)
    elif subcommand == "ack":
        event["server"].agreed_capabilities.update(capabilities)
        events.on("received.cap.ack").call(capabilities=capabilities,
           server=event["server"])

    if subcommand == "ack" or subcommand == "nak":
        ack = subcommand == "ack"
        for capability in capabilities:
            cap_obj = event["server"].capability_queue[capability]
            del event["server"].capability_queue[capability]
            if ack:
                cap_obj.ack()
            else:
                cap_obj.nak()

        if (event["server"].cap_started and
                not event["server"].capability_queue and
                not event["server"].waiting_for_capabilities()):
            event["server"].cap_started = False
            event["server"].send_capability_end()

def authenticate(events, event):
    events.on("received.authenticate").call(message=event["args"][0],
        server=event["server"])