<?php

namespace BitApps\PiPro\src\Integrations\FluentBoards;

use BitApps\Pi\Config;
use BitApps\Pi\src\Authorization\AuthorizationFactory;
use BitApps\Pi\src\Authorization\AuthorizationType;
use BitApps\Pi\src\Flow\NodeInfoProvider;
use BitApps\PiPro\Deps\BitApps\WPKit\Http\Client\HttpClient;
use BitApps\PiPro\Deps\BitApps\WPValidator\Validator;

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


final class FluentBoardsServices
{
    private NodeInfoProvider $nodeInfoProvider;

    private HttpClient $httpClient;

    private array $allowedMethods = ['get', 'post', 'put', 'delete'];

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

    public function listAllBoards(): array
    {
        return $this->fetchAllData();
    }

    public function getSingleBoard(): array
    {
        return $this->getDataById();
    }

    public function createBoard(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'title'       => ['required', 'string'],
            'description' => ['required', 'string'],
            'type'        => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient->setBody(['board' => (object) $fieldMappings]);

        return [
            'response'    => $this->httpClient->post(),
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function updateBoard(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'title'    => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient->setBody($fieldMappings);

        $response = $this->httpClient->put($fieldMappings['board_id']);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function deleteBoard(): array
    {
        return $this->boardAction(null, 'delete');
    }

    public function archiveBoard(): array
    {
        return $this->boardAction('archive-board');
    }

    public function restoreBoard(): array
    {
        return $this->boardAction('restore-board');
    }

    public function duplicateBoard(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $result = $this->httpClient->get($fieldMappings['id']);

        if ($this->httpClient->getResponseCode() !== 200 || empty($result->board->title)) {
            return [
                'response'    => $result,
                'payload'     => $fieldMappings,
                'status_code' => $this->httpClient->getResponseCode()
            ];
        }

        $boardName = $result->board->title . ' - Copy';
        $body = [
            'board'           => (object) ['title' => $boardName],
            'isWithTasks'     => 'yes',
            'isWithLabels'    => 'yes',
            'isWithTemplates' => 'no'
        ];

        $this->httpClient->setBody($body);

        $response = $this->httpClient->post($fieldMappings['id'] . '/duplicate-board');

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function getBoardMembers(): array
    {
        return $this->boardAction('users', 'get');
    }

    public function getBoardActivities(): array
    {
        return $this->boardAction('activities', 'get', true);
    }

    public function listAllTasks(): array
    {
        return $this->boardAction('tasks', 'get');
    }

    public function getSingleTask(): array
    {
        return $this->taskAction();
    }

    public function createTask(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'stage_id' => ['required', 'integer'],
            'title'    => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        if (isset($fieldMappings['is_template'])) {
            $fieldMappings['is_template'] = (string) $fieldMappings['is_template'];
        }

        $this->httpClient->setBody(['task' => (object) $fieldMappings]);

        $response = $this->httpClient->post($fieldMappings['board_id'] . '/tasks');

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function deleteTask(): array
    {
        return $this->taskAction(null, 'delete');
    }

    public function moveTask(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id'     => ['required', 'integer'],
            'task_id'      => ['required', 'integer'],
            'new_stage_id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $body = [
            'newStageId' => $fieldMappings['new_stage_id'],
            'newIndex'   => $fieldMappings['new_index'] ?? 1,
        ];

        if (isset($fieldMappings['new_board_id'])) {
            $body['newBoardId'] = $fieldMappings['new_board_id'];
        }

        $this->httpClient->setBody($body);

        $endpoint = $fieldMappings['board_id'] . '/tasks/' . $fieldMappings['task_id'] . '/move-task';
        $response = $this->httpClient->put($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function cloneTask(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'task_id'  => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $endpoint = $fieldMappings['board_id'] . '/tasks/' . $fieldMappings['task_id'];
        $result = $this->httpClient->get($endpoint);

        if (
            $this->httpClient->getResponseCode() !== 200
            || empty($result->task->title)
            || empty($result->task->stage_id)
        ) {
            return [
                'response'    => $result,
                'payload'     => $fieldMappings,
                'status_code' => $this->httpClient->getResponseCode()
            ];
        }

        $body = [
            'title'      => $result->task->title . ' (Cloned)',
            'stage_id'   => $result->task->stage_id,
            'assignee'   => true,
            'subtask'    => false,
            'label'      => true,
            'attachment' => true,
            'comment'    => true
        ];

        $this->httpClient->setBody($body);

        $endpoint = $fieldMappings['board_id'] . '/tasks/' . $fieldMappings['task_id'] . '/clone-task';
        $response = $this->httpClient->post($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function getTaskComments(): array
    {
        return $this->taskAction('comments');
    }

    public function getTaskActivities(): array
    {
        return $this->taskAction('activities');
    }

    public function createStage(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'title'    => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient->setBody($fieldMappings);

        $response = $this->httpClient->post($fieldMappings['board_id'] . '/stage-create');

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function archiveStage(): array
    {
        return $this->stageAction('archive-stage');
    }

    public function restoreStage(): array
    {
        return $this->stageAction('restore-stage');
    }

    public function archiveAllTasksInStage(): array
    {
        return $this->stageAction('stage', 'archive-all-task');
    }

    public function getArchivedStages(): array
    {
        return $this->boardAction('archived-stages', 'get', true);
    }

    public function getStageTaskAvailablePositions(): array
    {
        return $this->stageAction('stage-task-available-positions', null, 'get');
    }

    public function listAllLabels(): array
    {
        return $this->boardAction('labels', 'get');
    }

    public function createLabel(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'color'    => ['required', 'string'],
            'bg_color' => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient->setBody($fieldMappings);

        $response = $this->httpClient->post($fieldMappings['board_id'] . '/labels');

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function updateLabel(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'label_id' => ['required', 'integer'],
            'bg_color' => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient->setBody($fieldMappings);

        $response = $this->httpClient->put($fieldMappings['board_id'] . '/labels/' . $fieldMappings['label_id']);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function deleteLabel(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'label_id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $endpoint = $fieldMappings['board_id'] . '/labels/' . $fieldMappings['label_id'];
        $response = $this->httpClient->delete($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function getLabelsUsedInTasks(): array
    {
        return $this->boardAction('labels/used-in-tasks', 'get');
    }

    public function getTaskLabels(): array
    {
        return $this->taskAction('labels');
    }

    public function assignLabelsToTask(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'task_id'  => ['required', 'integer'],
            'label_id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient->setBody(
            [
                'taskId'  => $fieldMappings['task_id'],
                'labelId' => $fieldMappings['label_id'],
            ]
        );

        $endpoint = $fieldMappings['board_id'] . '/labels/task';
        $response = $this->httpClient->post($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function removeLabelFromTask(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'task_id'  => ['required', 'integer'],
            'label_id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $endpoint = $fieldMappings['board_id'] . '/tasks/' . $fieldMappings['task_id'] . '/labels/' . $fieldMappings['label_id'];
        $response = $this->httpClient->delete($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function listTaskComments(): array
    {
        return $this->taskAction('comments', 'get', true);
    }

    public function createComment(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'task_id'  => ['required', 'integer'],
            'comment'  => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient->setBody(
            [
                'comment'      => $fieldMappings['comment'],
                'comment_type' => 'comment',
                'comment_by'   => get_current_user_id(),
            ]
        );

        $endpoint = $fieldMappings['board_id'] . '/tasks/' . $fieldMappings['task_id'] . '/comments';
        $response = $this->httpClient->post($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function deleteComment(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id'   => ['required', 'integer'],
            'comment_id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $endpoint = $fieldMappings['board_id'] . '/tasks/comments/' . $fieldMappings['comment_id'];
        $response = $this->httpClient->delete($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function listSubtasks(): array
    {
        return $this->taskAction('subtasks');
    }

    public function createSubtask(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'task_id'  => ['required', 'integer'],
            'group_id' => ['required', 'integer'],
            'title'    => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient->setBody($fieldMappings);

        $endpoint = $fieldMappings['board_id'] . '/tasks/' . $fieldMappings['task_id'] . '/subtasks';

        $response = $this->httpClient->post($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function createSubtaskGroup(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'task_id'  => ['required', 'integer'],
            'title'    => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient->setBody($fieldMappings);

        $endpoint = $fieldMappings['board_id'] . '/tasks/' . $fieldMappings['task_id'] . '/subtask-group';

        $response = $this->httpClient->post($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function deleteSubtask(): array
    {
        return $this->taskAction('delete-subtask', 'delete', false, 'subtask_id');
    }

    public function cloneSubtask(): array
    {
        return $this->taskAction('clone-subtask', 'post', false, 'subtask_id');
    }

    public function listFolders(): array
    {
        $this->httpClient = $this->initializeHttpClient('fluent-boards/v2/admin/folders');

        return $this->fetchAllData();
    }

    public function createFolder(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'title' => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient = $this->initializeHttpClient('fluent-boards/v2/admin/folders');
        $this->httpClient->setBody(['title' => $fieldMappings['title']]);

        return [
            'response'    => $this->httpClient->post(),
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function updateFolder(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'folder_id' => ['required', 'integer'],
            'title'     => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient = $this->initializeHttpClient('fluent-boards/v2/admin/folders/');
        $this->httpClient->setBody(['title' => $fieldMappings['title']]);

        $response = $this->httpClient->put($fieldMappings['folder_id']);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function deleteFolder(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'folder_id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient = $this->initializeHttpClient('fluent-boards/v2/admin/folders/');

        $response = $this->httpClient->delete($fieldMappings['folder_id']);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function addBoardsToFolder(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'folder_id' => ['required', 'integer'],
            'board_ids' => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient = $this->initializeHttpClient('fluent-boards/v2/admin/folders/');
        $this->httpClient->setBody(
            [
                'boardIds' => array_map('trim', explode(',', $fieldMappings['board_ids']))
            ]
        );

        $response = $this->httpClient->post($fieldMappings['folder_id'] . '/add-board');

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function removeBoardFromFolder(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'folder_id' => ['required', 'integer'],
            'board_id'  => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient = $this->initializeHttpClient('fluent-boards/v2/admin/folders/');
        $this->httpClient->setBody($fieldMappings);

        $response = $this->httpClient->post($fieldMappings['folder_id'] . '/remove-board');

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function listAllUsers(): array
    {
        $this->httpClient = $this->initializeHttpClient('fluent-boards/v2/fluent-boards-users');

        return $this->fetchAllData();
    }

    public function searchUsers(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'display_name' => ['required', 'string'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient = $this->initializeHttpClient('fluent-boards/v2/search-fluent-boards-users');
        $this->httpClient->setBody(
            [
                'searchInput' => $fieldMappings['display_name'],
            ]
        );

        return [
            'response'    => $this->httpClient->get(),
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function getProjectMembers(): array
    {
        return $this->boardAction('users', 'get');
    }

    public function addMembersToProject(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id'  => ['required', 'integer'],
            'member_id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient->setBody(
            [
                'memberId'     => $fieldMappings['member_id'],
                'isViewerOnly' => isset($fieldMappings['is_viewer_only']) && $fieldMappings['is_viewer_only'] ? 'yes' : 'no',
            ]
        );

        $response = $this->httpClient->post($fieldMappings['board_id'] . '/add-members');

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function removeUserFromProject(): array
    {
        return $this->userAction('remove', 'post');
    }

    public function makeUserManager(): array
    {
        return $this->userAction('make-manager', 'post');
    }

    public function removeManagerRole(): array
    {
        return $this->userAction('remove-manager', 'post');
    }

    public function makeUserMember(): array
    {
        return $this->userAction('make-member', 'post');
    }

    public function makeUserViewer(): array
    {
        return $this->userAction('make-viewer', 'post');
    }

    public function removeUserFromBoard(): array
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'user_id'  => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $this->httpClient = $this->initializeHttpClient('fluent-boards/v2/remove-user-from-board');
        $this->httpClient->setBody(
            [
                'boardId' => $fieldMappings['board_id'],
                'userId'  => $fieldMappings['user_id'],
            ]
        );

        return [
            'response'    => $this->httpClient->delete(),
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    public function getProjectAssignees(): array
    {
        return $this->boardAction('assignees', 'get');
    }

    /**
     * Validate field map.
     *
     * @param array $fieldMappings
     * @param array $validationRules
     * @param null|array $payload
     *
     * @return null|array
     */
    public static function validateFieldMap($fieldMappings, $validationRules, $payload = null)
    {
        $validator = new Validator();
        $validation = $validator->make($fieldMappings, $validationRules);

        if ($validation->fails()) {
            return [
                'response'    => $validation->errors(),
                'payload'     => $payload ?? $fieldMappings,
                'status_code' => 400
            ];
        }
    }

    /**
     * Perform board-related actions (delete, archive, restore, members, tasks,
     * archived stages, activities).
     *
     * @param null|string $endpoint endpoint suffix (appended after the board ID) or null to use the ID only
     * @param string $method HTTP method to call on the client (get/post/put/delete)
     * @param bool $paginated whether the endpoint expects pagination query params
     *
     * @return array
     */
    public function boardAction($endpoint = null, $method = 'put', $paginated = false)
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        if (!\in_array($method, $this->allowedMethods)) {
            return [
                'response'    => ['error' => 'Invalid HTTP method'],
                'payload'     => $fieldMappings,
                'status_code' => 400
            ];
        }

        $endpoint = $endpoint ? $fieldMappings['id'] . '/' . $endpoint : $fieldMappings['id'];

        if ($paginated) {
            $this->setQueryParams(
                [
                    'per_page' => $fieldMappings['per_page'] ?? 10,
                    'page'     => $fieldMappings['page'] ?? 1,
                ]
            );
        }

        $response = $this->httpClient->{$method}($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    /**
     * Perform task-related actions (delete, move, clone, comments, activities).
     *
     * @param null|string $endpoint Optional endpoint suffix for the task action (e.g. 'comments').
     * @param string $method HTTP method to call on the client (get/post/put/delete)
     * @param bool $paginated if truthy, pagination query params will be set from the field map
     * @param mixed $taskIdKeyName
     *
     * @return array
     */
    public function taskAction($endpoint = null, $method = 'get', $paginated = false, $taskIdKeyName = 'task_id')
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id'     => ['required', 'integer'],
            $taskIdKeyName => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        if (!\in_array($method, $this->allowedMethods)) {
            return [
                'response'    => ['error' => 'Invalid HTTP method'],
                'payload'     => $fieldMappings,
                'status_code' => 400
            ];
        }

        if ($paginated) {
            $this->setQueryParams(
                [
                    'per_page' => $fieldMappings['per_page'] ?? 10,
                    'page'     => $fieldMappings['page'] ?? 1,
                ]
            );
        }

        $endpoint = $fieldMappings['board_id'] . '/tasks/' . $fieldMappings[$taskIdKeyName] . ($endpoint ? '/' . $endpoint : '');
        $response = $this->httpClient->{$method}($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    /**
     * Perform stage-related actions (archive, restore, or archive all tasks).
     *
     * @param string $action The stage action to perform (e.g. 'archive-stage', 'restore-stage', 'stage').
     * @param null|string $endpoint optional additional endpoint suffix
     * @param string $method HTTP method to call on the client (get/post/put/delete)
     *
     * @return array
     */
    public function stageAction($action, $endpoint = null, $method = 'put')
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'stage_id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        if (!\in_array($method, $this->allowedMethods)) {
            return [
                'response'    => ['error' => 'Invalid HTTP method'],
                'payload'     => $fieldMappings,
                'status_code' => 400
            ];
        }

        $endpoint = $fieldMappings['board_id'] . '/' . $action . '/' . $fieldMappings['stage_id'] . ($endpoint ? '/' . $endpoint : '');
        $response = $this->httpClient->{$method}($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    /**
     * Perform user-related actions on a board (make manager, remove, make member/viewer, etc.).
     *
     * @param null|string $endpoint Optional endpoint suffix for user actions (e.g. 'make-manager').
     * @param string $method HTTP method to call on the client (get/post/put/delete)
     *
     * @return array
     */
    public function userAction($endpoint = null, $method = 'put')
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'board_id' => ['required', 'integer'],
            'user_id'  => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        if (!\in_array($method, $this->allowedMethods)) {
            return [
                'response'    => ['error' => 'Invalid HTTP method'],
                'payload'     => $fieldMappings,
                'status_code' => 400
            ];
        }

        $endpoint = $fieldMappings['board_id'] . '/user/' . $fieldMappings['user_id'] . ($endpoint ? '/' . $endpoint : '');
        $response = $this->httpClient->{$method}($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    /**
     * Get data by ID from the given endpoint.
     *
     * @return array
     */
    private function getDataById()
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $rules = [
            'id' => ['required', 'integer'],
        ];

        $errors = self::validateFieldMap($fieldMappings, $rules);

        if ($errors) {
            return $errors;
        }

        $response = $this->httpClient->get($fieldMappings['id']);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    /**
     * Fetch all data from the given endpoint with pagination support.
     *
     * @param string $endpoint
     *
     * @return array
     */
    private function fetchAllData($endpoint = null)
    {
        $fieldMappings = $this->nodeInfoProvider->getFieldMapData();

        $this->setQueryParams(
            [
                'per_page' => $fieldMappings['per_page'] ?? 10,
                'page'     => $fieldMappings['page'] ?? 1,
            ]
        );

        $response = $this->httpClient->get($endpoint);

        return [
            'response'    => $response,
            'payload'     => $fieldMappings,
            'status_code' => $this->httpClient->getResponseCode()
        ];
    }

    /**
     * Set query parameters for the HTTP client.
     */
    private function setQueryParams(array $params)
    {
        $this->httpClient->setQueryParams($params);
    }

    /**
     * Initialize HttpClient with authorization and base URL.
     */
    private function initializeHttpClient(?string $endpoint = null): HttpClient
    {
        $connectionId = $this->nodeInfoProvider->getFieldMapConfigs('connection-id.value');

        $authHandler = AuthorizationFactory::getAuthorizationHandler(
            AuthorizationType::BASIC_AUTH,
            $connectionId
        );

        if (!$endpoint) {
            $endpoint = 'fluent-boards/v2/projects/';
        }

        $wpApiURL = Config::get('WP_API_URL');

        return new HttpClient(
            [
                'base_uri' => $wpApiURL['base'] . $endpoint,
                'headers'  => [
                    'Authorization' => $authHandler->getAccessToken(),
                    'Content-Type'  => 'application/json',
                ],
            ]
        );
    }
}
