# -*- coding: utf-8 -*-
# cython: language_level=3
# Copyright (c) 2021-present VincentRPS

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE
from discord.types import Dict

from ..guild import ScheduledEvent
from ..state import ConnectionState, member_cacher
from .channels import (
    OnChannelCreate,
    OnChannelDelete,
    OnChannelPinsUpdate,
    OnChannelUpdate,
    OnThreadCreate,
    OnThreadDelete,
    OnThreadListSync,
    OnThreadMembersUpdate,
    OnThreadMemberUpdate,
    OnThreadUpdate,
)
from .etc import (
    OnInviteCreate,
    OnInviteDelete,
    OnStageInstanceCreate,
    OnStageInstanceDelete,
    OnStageInstanceEdit,
    OnTyping,
    OnUserUpdate,
    OnWebhooksUpdate,
)
from .guilds import (
    OnGuildBan,
    OnGuildBanRemove,
    OnGuildEmojisUpdate,
    OnGuildIntegrationsUpdate,
    OnGuildJoin,
    OnGuildLeave,
    OnGuildStickersUpdate,
    OnGuildUpdate,
    OnMemberJoin,
    OnMemberLeave,
    OnMemberUpdate,
    OnRoleCreate,
    OnRoleDelete,
    OnRoleUpdate,
    OnScheduledEventCreate,
    OnScheduledEventDelete,
    OnScheduledEventJoin,
    OnScheduledEventLeave,
    OnScheduledEventUpdate,
)
from .interactions import OnInteraction
from .messages import (
    OnMessage,
    OnMessageDelete,
    OnMessageDeleteBulk,
    OnMessageEdit,
    OnMessageReactionAdd,
    OnMessageReactionRemove,
    OnMessageReactionRemoveAll,
    OnMessageReactionRemoveEmoji,
)


# https://discord.dev/topics/gateway#commands-and-events-gateway-events
class Cataloger:
    def __init__(self, data: Dict, dis, state: ConnectionState):

        # guilds
        if data['t'] == 'GUILD_CREATE':
            state.guilds.new(data['d']['id'], data['d'])
            # roles, channels
            for channel in data['d']['channels']:
                state.channels.new(channel['id'], channel)
            for role in data['d']['roles']:
                state.roles.new(role['id'], role)
            for event in data['d']['guild_scheduled_events']:
                even = ScheduledEvent(event)
                state.guild_events.new(even.id, even)
            dis.dispatch('RAW_GUILD_CREATE', data['d'])
            OnGuildJoin(data['d'], dis, state)

        elif data['t'] == 'GUILD_DELETE':
            dis.dispatch('RAW_GUILD_DELETE', data['d'])
            OnGuildLeave(data['d'], dis, state)

        elif data['t'] == 'GUILD_UPDATE':
            dis.dispatch('RAW_GUILD_UPDATE', data['d'])
            OnGuildUpdate(data['d'], dis, state)

        elif data['t'] == 'GUILD_BAN_ADD':
            dis.dispatch('RAW_BAN_ADD', data['d'])
            OnGuildBan(data['d'], dis, state)

        elif data['t'] == 'GUILD_BAN_REMOVE':
            dis.dispatch('RAW_BAN_REMOVE', data['d'])
            OnGuildBanRemove(data['d'], dis, state)

        elif data['t'] == 'GUILD_EMOJIS_UPDATE':
            dis.dispatch('RAW_EMOJIS_UPDATE', data['d'])
            OnGuildEmojisUpdate(data['d'], dis, state)

        elif data['t'] == 'GUILD_STICKERS_UPDATE':
            dis.dispatch('RAW_STICKERS_UPDATE', data['d'])
            OnGuildStickersUpdate(data['d'], dis, state)

        elif data['t'] == 'GUILD_INTEGRATIONS_UPDATE':
            dis.dispatch('RAW_GUILD_INTEGRATIONS_UPDATE', data['d'])
            OnGuildIntegrationsUpdate(data['d'], dis, state)

        elif data['t'] == 'GUILD_MEMBER_ADD':
            dis.dispatch('RAW_GUILD_MEMBER_ADD', data['d'])
            OnMemberJoin(data['d'], dis, state)

        elif data['t'] == 'GUILD_MEMBER_REMOVE':
            dis.dispatch('RAW_GUILD_MEMBER_REMOVE', data['d'])
            OnMemberLeave(data['d'], dis, state)

        elif data['t'] == 'GUILD_MEMBER_UPDATE':
            dis.dispatch('RAW_MEMBER_UPDATE', data['d'])
            OnMemberUpdate(data['d'], dis, state)

        elif data['t'] == 'GUILD_MEMBERS_CHUNK':
            dis.dispatch('RAW_GUILD_MEMBERS_CHUNK', data['d'])
            member_cacher(state, data['d']['members'])

        elif data['t'] == 'ROLE_CREATE':
            dis.dispatch('RAW_ROLE_CREATE', data['d'])
            OnRoleCreate(data['d'], dis, state)

        elif data['t'] == 'ROLE_UPDATE':
            dis.dispatch('RAW_ROLE_UPDATE', data['d'])
            OnRoleUpdate(data['d'], dis, state)

        elif data['t'] == 'ROLE_DELETE':
            dis.dispatch('RAW_ROLE_DELETE', data['d'])
            OnRoleDelete(data['d'], dis, state)

        elif data['t'] == 'GUILD_SCHEDULED_EVENT_CREATE':
            dis.dispatch('RAW_SCHEDULED_EVENT_CREATE', data['d'])
            OnScheduledEventCreate(data['d'], dis, state)

        elif data['t'] == 'GUILD_SCHEDULED_EVENT_UPDATE':
            dis.dispatch('RAW_SCHEDULED_EVENT_UPDATE', data['d'])
            OnScheduledEventUpdate(data['d'], dis, state)

        elif data['t'] == 'GUILD_SCHEDULED_EVENT_DELETE':
            dis.dispatch('RAW_SCHEDULED_EVENT_DELETE', data['d'])
            OnScheduledEventDelete(data['d'], dis, state)

        elif data['t'] == 'GUILD_SCHEDULED_EVENT_USER_ADD':
            dis.dispatch('RAW_SCHEDULED_EVENT_JOIN', data['d'])
            OnScheduledEventJoin(data['d'], dis, state)

        elif data['t'] == 'GUILD_SCHEDULED_EVENT_USER_REMOVE':
            dis.dispatch('RAW_SCHEDULED_EVENT_LEAVE', data['d'])
            OnScheduledEventLeave(data['d'], dis, state)

        # channels
        elif data['t'] == 'CHANNEL_CREATE':
            dis.dispatch('RAW_CHANNEL_CREATE', data['d'])
            OnChannelCreate(data['d'], dis, state)

        elif data['t'] == 'CHANNEL_UPDATE':
            dis.dispatch('RAW_CHANNEL_UPDATE', data['d'])
            OnChannelUpdate(data['d'], dis, state)

        elif data['t'] == 'CHANNEL_DELETE':
            dis.dispatch('RAW_CHANNEL_DELETE', data['d'])
            OnChannelDelete(data['d'], dis, state)

        elif data['t'] == 'CHANNEL_PINS_UPDATE':
            dis.dispatch('RAW_CHANNEL_PINS_UPDATE', data['t'])
            OnChannelPinsUpdate(data['d'], dis, state)

        elif data['t'] == 'THREAD_CREATE':
            dis.dispatch('RAW_THREAD_CREATE', data['d'])
            OnThreadCreate(data['d'], dis, state)

        elif data['t'] == 'THREAD_UPDATE':
            dis.dispatch('RAW_THREAD_UPDATE', data['d'])
            OnThreadUpdate(data['d'], dis, state)

        elif data['t'] == 'THREAD_DELETE':
            dis.dispatch('RAW_THREAD_DELETE', data['d'])
            OnThreadDelete(data['d'], dis, state)

        elif data['t'] == 'THREAD_LIST_SYNC':
            dis.dispatch('RAW_THREAD_LIST_SYNC', data['d'])
            OnThreadListSync(data['d'], dis, state)

        elif data['t'] == 'THREAD_MEMBER_UPDATE':
            dis.dispatch('RAW_THREAD_MEMBER_UPDATE', data['d'])
            OnThreadMemberUpdate(data['d'], dis, state)

        elif data['t'] == 'THREAD_MEMBERS_UPDATE':
            dis.dispatch('RAW_THREAD_MEMBERS_UPDATE', data['d'])
            OnThreadMembersUpdate(data['d'], dis, state)

        # messages
        elif data['t'] == 'MESSAGE_CREATE':
            dis.dispatch('RAW_MESSAGE', data['d'])
            OnMessage(data['d'], dis, state)

        elif data['t'] == 'MESSAGE_DELETE':
            dis.dispatch('RAW_MESSAGE_DELETE', data['d'])
            OnMessageDelete(data['d'], dis, state)

        elif data['t'] == 'MESSAGE_UPDATE':
            dis.dispatch('RAW_MESSAGE_EDIT', data['d'])
            OnMessageEdit(data['d'], dis, state)

        elif data['t'] == 'MESSAGE_DELETE_BULK':
            dis.dispatch('RAW_MESSAGE_DELETE_BULK', data['d'])
            OnMessageDeleteBulk(data['d'], dis, state)

        elif data['t'] == 'MESSAGE_REACTION_ADD':
            dis.dispatch('RAW_MESSAGE_REACTION_ADD', data['d'])
            OnMessageReactionAdd(data['d'], dis, state)

        elif data['t'] == 'MESSAGE_REACTION_REMOVE':
            dis.dispatch('RAW_MESSAGE_REACTION_REMOVE', data['d'])
            OnMessageReactionRemove(data['d'], dis, state)

        elif data['t'] == 'MESSAGE_REACTION_REMOVE_ALL':
            dis.dispatch('RAW_MESSAGE_REACTION_REMOVE_ALL', data['d'])
            OnMessageReactionRemoveAll(data['d'], dis, state)

        elif data['t'] == 'MESSAGE_REACTION_REMOVE_EMOJI':
            dis.dispatch('RAW_MESSAGE_REACTION_REMOVE_EMOJI', data['d'])
            OnMessageReactionRemoveEmoji(data['d'], dis, state)

        # interactions
        elif data['t'] == 'INTERACTION_CREATE':
            dis.dispatch('RAW_INTERACTION', data['d'])
            OnInteraction(data['d'], dis, state)

        # etc
        elif data['t'] == 'TYPING_START':
            dis.dispatch('RAW_TYPING_START', data['d'])
            OnTyping(data['d'], dis, state)

        elif data['t'] == 'STAGE_INSTANCE_CREATE':
            dis.dispatch('RAW_STAGE_INSTANCE_CREATE', data['d'])
            OnStageInstanceCreate(data['d'], dis, state)

        elif data['t'] == 'STAGE_INSTANCE_DELETE':
            dis.dispatch('RAW_STAGE_INSTANCE_DELETE', data['d'])
            OnStageInstanceDelete(data['d'], dis, state)

        elif data['t'] == 'STAGE_INSTANCE_UPDATE':
            dis.dispatch('RAW_STAGE_INSTANCE_UPDATE', data['d'])
            OnStageInstanceEdit(data['d'], dis, state)

        elif data['t'] == 'USER_UPDATE':
            dis.dispatch('RAW_USER_UPDATE', data['d'])
            OnUserUpdate(data['d'], dis, state)

        elif data['t'] == 'WEBHOOKS_UPDATE':
            dis.dispatch('RAW_WEBHOOKS_UPDATE', data['d'])
            OnWebhooksUpdate(data['d'], dis, state)

        elif data['t'] == 'INVITE_CREATE':
            dis.dispatch('RAW_INVITE_CREATE', data['d'])
            OnInviteCreate(data['d'], dis, state)

        elif data['t'] == 'INVITE_DELETE':
            dis.dispatch('RAW_INVITE_DELETE', data['d'])
            OnInviteDelete(data['d'], dis, state)

        # there are some non-included events.
        else:
            dis.dispatch(f'RAW_{data["t"]}', data['d'])
