<?php

declare(strict_types=1);

/*
 * This file is a part of the DiscordPHP project.
 *
 * Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
 *
 * This file is subject to the MIT license that is bundled
 * with this source code in the LICENSE.md file.
 */

namespace Discord\WebSockets;

/**
 * Contains constants used in websockets.
 *
 * @link https://discord.com/developers/docs/topics/opcodes-and-status-codes
 *
 * @since 3.2.1
 */
class Op
{
    /**
     * Gateway Opcodes.
     *
     * All gateway events in Discord are tagged with an opcode that denotes the
     * payload type. Your connection to our gateway may also sometimes close.
     * When it does, you will receive a close code that tells you what happened.
     *
     * @link https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-opcodes
     */

    /** Dispatches an event. */
    public const OP_DISPATCH = 0;
    /** Used for ping checking. */
    public const OP_HEARTBEAT = 1;
    /** Used for client handshake. */
    public const OP_IDENTIFY = 2;
    /** Used to update the client presence. */
    public const OP_UPDATE_PRESENCE = 3;
    /** @deprecated 10.18.31 Use `OP_UPDATE_PRESENCE` */
    public const OP_PRESENCE_UPDATE = self::OP_UPDATE_PRESENCE;
    /** Used to join/move/leave voice channels. */
    public const OP_UPDATE_VOICE_STATE = 4;
    /** @deprecated 10.18.31 Use `OP_UPDATE_VOICE_STATE` */
    public const OP_VOICE_STATE_UPDATE = self::OP_UPDATE_VOICE_STATE;
    /** Used for voice ping checking. */
    public const OP_VOICE_SERVER_PING = 5;
    /** Used to resume a closed connection. */
    public const OP_RESUME = 6;
    /** Used to redirect clients to a new gateway. */
    public const OP_RECONNECT = 7;
    /** Used to request member chunks. */
    public const OP_REQUEST_GUILD_MEMBERS = 8;
    /** @deprecated 10.18.31 Use `OP_REQUEST_GUILD_MEMBERS` */
    public const OP_GUILD_MEMBER_CHUNK = self::OP_REQUEST_GUILD_MEMBERS;
    /** Used to notify clients when they have an invalid session. */
    public const OP_INVALID_SESSION = 9;
    /** Used to pass through the heartbeat interval. */
    public const OP_HELLO = 10;
    /** Used to acknowledge heartbeats. */
    public const OP_HEARTBEAT_ACK = 11;
    /** Request soundboard sounds. */
    public const OP_REQUEST_SOUNDBOARD_SOUNDS = 31;

    /**
     * Voice Opcodes.
     *
     * Our voice gateways have their own set of opcodes and close codes.
     *
     * @link https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice-voice-opcodes
     */

    /** Used to begin a voice WebSocket connection. */
    public const VOICE_IDENTIFY = 0;
    /** Used to select the voice protocol. */
    public const VOICE_SELECT_PROTOCOL = 1;
    /** @deprecated use VOICE_SELECT_PROTOCOL */
    public const VOICE_SELECT_PROTO = self::VOICE_SELECT_PROTOCOL;
    /** Used to complete the WebSocket handshake. */
    public const VOICE_READY = 2;
    /** Used to keep the WebSocket connection alive. */
    public const VOICE_HEARTBEAT = 3;
    /** Used to describe the session. */
    public const VOICE_SESSION_DESCRIPTION = 4;
    /** @deprecated use VOICE_SESSION_DESCRIPTION */
    public const VOICE_DESCRIPTION = self::VOICE_SESSION_DESCRIPTION;
    /** Used to identify which users are speaking. */
    public const VOICE_SPEAKING = 5;
    /** Sent by the Discord servers to acknowledge heartbeat */
    public const VOICE_HEARTBEAT_ACK = 6;
    /** Resume a connection. */
    public const VOICE_RESUME = 7;
    /** Hello packet used to pass heartbeat interval */
    public const VOICE_HELLO = 8;
    /** Acknowledge a successful session resume. */
    public const VOICE_RESUMED = 9;
    /** One or more clients have connected to the voice channel */
    public const VOICE_CLIENT_CONNECT = 11;
    /** A client has disconnected from the voice channel. */
    public const VOICE_CLIENT_DISCONNECT = 13;
    /** Undocumented. */
    public const VOICE_CLIENT_UNKNOWN_15 = 15;
    /** Undocumented. */
    public const VOICE_CLIENT_UNKNOWN_18 = 18;
    /** Undocumented. Assumed to be the platform type in which the user is. */
    public const VOICE_CLIENT_PLATFORM = 20;

    /** A downgrade from the DAVE protocol is upcoming. */
    public const VOICE_DAVE_PREPARE_TRANSITION = 21;
    /** Execute a previously announced protocol transition. */
    public const VOICE_DAVE_EXECUTE_TRANSITION = 22;
    /** Acknowledge readiness previously announced transition. */
    public const VOICE_DAVE_TRANSITION_READY = 23;
    /** A DAVE protocol version or group change is upcoming. */
    public const VOICE_DAVE_PREPARE_EPOCH = 24;
    /** Credential and public key for MLS external sender. */
    public const VOICE_DAVE_MLS_EXTERNAL_SENDER = 25;
    /** MLS Key Package for pending group member. */
    public const VOICE_DAVE_MLS_KEY_PACKAGE = 26;
    /** MLS Proposals to be appended or revoked. */
    public const VOICE_DAVE_MLS_PROPOSALS = 27;
    /** MLS Commit with optional MLS Welcome messages. */
    public const VOICE_DAVE_MLS_COMMIT_WELCOME = 28;
    /** MLS Commit to be processed for upcoming transition. */
    public const VOICE_DAVE_MLS_ANNOUNCE_COMMIT_TRANSITION = 29;
    /** MLS Welcome to group for upcoming transition. */
    public const VOICE_DAVE_MLS_WELCOME = 30;
    /** Flag invalid commit or welcome, request re-add */
    public const VOICE_DAVE_MLS_INVALID_COMMIT_WELCOME = 31;

    /**
     * Gateway Close Event Codes.
     *
     * In order to prevent broken reconnect loops, you should consider some
     * close codes as a signal to stop reconnecting. This can be because your
     * token expired, or your identification is invalid. This table explains
     * what the application defined close codes for the gateway are, and which
     * close codes you should not attempt to reconnect.
     *
     * @link https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-close-event-codes
     */

    /** Normal close or heartbeat is invalid. */
    public const CLOSE_NORMAL = 1000;
    /** Abnormal close. */
    public const CLOSE_ABNORMAL = 1006;
    /** Unknown error. */
    public const CLOSE_UNKNOWN_ERROR = 4000;
    /** Unknown opcode was sent. */
    public const CLOSE_INVALID_OPCODE = 4001;
    /** Invalid message was sent. */
    public const CLOSE_INVALID_MESSAGE = 4002;
    /** Not authenticated. */
    public const CLOSE_NOT_AUTHENTICATED = 4003;
    /** Invalid token on IDENTIFY. */
    public const CLOSE_INVALID_TOKEN = 4004;
    /** Already authenticated. */
    public const CONST_ALREADY_AUTHD = 4005;
    /** Session is invalid. */
    public const CLOSE_INVALID_SESSION = 4006;
    /** Invalid RESUME sequence. */
    public const CLOSE_INVALID_SEQ = 4007;
    /** Too many messages sent. */
    public const CLOSE_TOO_MANY_MSG = 4008;
    /** Session timeout. */
    public const CLOSE_SESSION_TIMEOUT = 4009;
    /** Invalid shard. */
    public const CLOSE_INVALID_SHARD = 4010;
    /** Sharding required. */
    public const CLOSE_SHARDING_REQUIRED = 4011;
    /** Invalid API version. */
    public const CLOSE_INVALID_VERSION = 4012;
    /** Invalid intents. */
    public const CLOSE_INVALID_INTENTS = 4013;
    /** Disallowed intents. */
    public const CLOSE_DISALLOWED_INTENTS = 4014;

    /**
     * Voice Close Event Codes.
     *
     * @link https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice-voice-close-event-codes
     */

    /** Can't find the server. */
    public const CLOSE_VOICE_SERVER_NOT_FOUND = 4011;
    /** Unknown protocol. */
    public const CLOSE_VOICE_UNKNOWN_PROTO = 4012;
    /** Disconnected from channel. */
    public const CLOSE_VOICE_DISCONNECTED = 4014;
    /** Voice server crashed. */
    public const CLOSE_VOICE_SERVER_CRASH = 4015;
    /** Unknown encryption mode. */
    public const CLOSE_VOICE_UNKNOWN_ENCRYPT = 4016;
    /** You sent a malformed request. */
    public const CLOSE_VOICE_BAD_REQUEST = 4020;
    /** Disconnect due to rate limit exceeded. Should not reconnect. */
    public const CLOSE_VOICE_DISCONNECTED_RATE_LIMITED = 4021;
    /** Disconnect all clients due to call terminated (channel deleted, voice server changed, etc.). Should not reconnect. */
    public const CLOSE_VOICE_DISCONNECTED_CALL_TERMINATED = 4022;

    /**
     * Returns the critical event codes that we should not reconnect after.
     *
     * @return array
     */
    public static function getCriticalCloseCodes(): array
    {
        return [
            self::CLOSE_INVALID_TOKEN,
            self::CLOSE_SHARDING_REQUIRED,
            self::CLOSE_INVALID_SHARD,
            self::CLOSE_INVALID_VERSION,
            self::CLOSE_INVALID_INTENTS,
            self::CLOSE_DISALLOWED_INTENTS,
        ];
    }

    /**
     * Returns the critical event codes for a voice websocket.
     *
     * @return array
     */
    public static function getCriticalVoiceCloseCodes(): array
    {
        return [
            self::CLOSE_INVALID_SESSION,
            self::CLOSE_INVALID_TOKEN,
            self::CLOSE_VOICE_SERVER_NOT_FOUND,
            self::CLOSE_VOICE_UNKNOWN_PROTO,
            self::CLOSE_VOICE_UNKNOWN_ENCRYPT,
        ];
    }
}
