<?php

namespace BitApps\PiPro\src\Integrations\Discord;

if (!\defined('ABSPATH')) {
    exit;
}

use BitApps\Pi\src\Authorization\AuthorizationFactory;
use BitApps\Pi\src\Authorization\AuthorizationType;
use BitApps\Pi\src\Flow\NodeInfoProvider;
use BitApps\Pi\src\Interfaces\ActionInterface;
use BitApps\PiPro\Deps\BitApps\WPKit\Http\Client\HttpClient;
use InvalidArgumentException;

class DiscordAction implements ActionInterface
{
    public const BASE_URL = 'https://discord.com/api/v10';

    public const AUTH_TOKEN_URL = 'https://discord.com/api/oauth2/token';

    public $guiID = '';

    private NodeInfoProvider $nodeInfoProvider;

    private DiscordChannelService $channelService;

    private DiscordMessageService $messageService;

    private DiscordMemberService $memberService;

    public function __construct(NodeInfoProvider $nodeInfoProvider)
    {
        $this->nodeInfoProvider = $nodeInfoProvider;
    }

    public function execute(): array
    {
        $connectionId = $this->nodeInfoProvider->getFieldMapConfigs('connection-id.value');

        $tokenAuthorization = AuthorizationFactory::getAuthorizationHandler(
            AuthorizationType::OAUTH2,
            $connectionId
        );
        $authDetails = $tokenAuthorization->getAuthDetails();
        $botToken = $authDetails['extraData']->bot_token;
        $this->guiID = $authDetails['guild']->id;
        if (empty($botToken)) {
            return ['error' => 'Bot token is required'];
        }

        $httpClient = new HttpClient(
            ['headers' => [
                'Authorization' => 'Bot ' . $botToken,
                'Content-Type'  => 'application/json',
            ]
            ]
        );
        return $this->executeDiscordAction($httpClient);
    }

    private function executeDiscordAction($httpClient)
    {
        $discordAction = $this->nodeInfoProvider->getMachineSlug();

        $this->channelService = new DiscordChannelService($httpClient, static::BASE_URL);
        $this->messageService = new DiscordMessageService($httpClient, static::BASE_URL);
        $this->memberService = new DiscordMemberService($httpClient, static::BASE_URL);

        switch ($discordAction) {
            case 'createChannel':
                return $this->createChannel();

            case 'updateChannel':
                return $this->updateChannel();

            case 'getChannelByName':
                return $this->getChannelByName();

            case 'sendChannelMessage':
                return $this->sendChannelMessage();

            case 'findChannel':
                return $this->findChannel();

            case 'createChannelInvite':
                return $this->createChannelInvite();

            case 'sendDirectMessage':
                return $this->sendDirectMessage();

            case 'deleteMessage':
                return $this->deleteMessage();

            case 'getMessage':
                return $this->getMessage();

            case 'getManyMessages':
                return $this->getMessages();

            case 'reactWithEmoji':
                return $this->reactWithEmoji();

            case 'getManyMembers':
                return $this->getMembers();

            case 'addRoleToMember':
                return $this->addRoleToMember();

            case 'removeRoleFromMember':
                return $this->removeRoleFromMember();

            case 'findUser':
                return $this->findUser();

            case 'createNewForumPost':
                return $this->createNewForumPost();


            default:
                throw new InvalidArgumentException("Unknown action: {$discordAction}");
        }
    }

    private function createChannel()
    {
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->channelService->createChannel($this->guiID, $data);
    }

    private function updateChannel()
    {
        $channelId = $this->nodeInfoProvider->getFieldMapConfigs('channel-id.value');
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->channelService->updateChannel($channelId, $data);
    }

    private function getChannelByName()
    {
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->channelService->getChannelByName($this->guiID, $data);
    }

    private function sendChannelMessage()
    {
        $channelId = $this->nodeInfoProvider->getFieldMapConfigs('channel-id.value');
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->messageService->sendMessage($channelId, $data);
    }

    private function findChannel()
    {
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->channelService->findChannel($this->guiID, $data['search_query'], $data['channel_type']);
    }

    private function createChannelInvite()
    {
        $channelId = $this->nodeInfoProvider->getFieldMapConfigs('channel-id.value');
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->channelService->createChannelInvite($channelId, $data);
    }

    private function sendDirectMessage()
    {
        $userId = $this->nodeInfoProvider->getFieldMapConfigs('user-id.value');
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->messageService->sendDirectMessage($userId, $data);
    }

    private function deleteMessage()
    {
        $channelId = $this->nodeInfoProvider->getFieldMapConfigs('channel-id.value');
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->messageService->deleteMessage($channelId, $data['message_id']);
    }

    private function getMessage()
    {
        $channelId = $this->nodeInfoProvider->getFieldMapConfigs('channel-id.value');
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->messageService->getMessage($channelId, $data['message_id']);
    }

    private function getMessages()
    {
        $channelId = $this->nodeInfoProvider->getFieldMapConfigs('channel-id.value');
        $data = $this->nodeInfoProvider->getFieldMapData();
        $limit = isset($data['limit']) ? (int) $data['limit'] : 50;

        return $this->messageService->getMessages($channelId, $limit);
    }

    private function reactWithEmoji()
    {
        $channelId = $this->nodeInfoProvider->getFieldMapConfigs('channel-id.value');
        $data = $this->nodeInfoProvider->getFieldMapData();
        $messageId = $data['message_id'] ?? '';
        $emoji = $data['emoji'] ?? '';

        return $this->messageService->reactWithEmoji($channelId, $messageId, $emoji);
    }

    private function getMembers()
    {
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->memberService->getMembers($this->guiID, $data['member_limit']);
    }

    private function addRoleToMember()
    {
        $userId = $this->nodeInfoProvider->getFieldMapConfigs('user-id.value');
        $roleId = $this->nodeInfoProvider->getFieldMapConfigs('role-id.value');

        return $this->memberService->addRoleToMember($this->guiID, $userId, $roleId);
    }

    private function removeRoleFromMember()
    {
        $userId = $this->nodeInfoProvider->getFieldMapConfigs('user-id.value');
        $roleId = $this->nodeInfoProvider->getFieldMapConfigs('role-id.value');

        return $this->memberService->removeRoleFromMember($this->guiID, $userId, $roleId);
    }

    private function findUser()
    {
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->memberService->findUser($this->guiID, $data['search_query']);
    }

    private function createNewForumPost()
    {
        $channelId = $this->nodeInfoProvider->getFieldMapConfigs('channel-id.value');
        $data = $this->nodeInfoProvider->getFieldMapData();

        return $this->channelService->createForumPost($channelId, $data);
    }
}
