<?php

namespace EasyLinkAutomations\HTTP\Controllers\Actions;

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


use EasyLinkAutomations\HTTP\Response;
use EasyLinkAutomations\HTTP\Request\Request;
use EasyLinkAutomations\Models\Connection;

/**
 * Handles remote data fetching for Trello actions.
 */
final class TrelloController
{
    /**
     * Builds the Trello query string auth params from connection credentials.
     */
    private function buildAuth(int $connectionId): array
    {
        $connection = Connection::find($connectionId);
        if (!$connection) {
            return [];
        }

        $credentials = Connection::getCredentials($connection);
        $apiKey      = $credentials['api_key'] ?? '';
        $apiToken    = $credentials['api_token'] ?? '';

        if (empty($apiKey) || empty($apiToken)) {
            return [];
        }

        return [
            'auth' => 'key=' . rawurlencode($apiKey) . '&token=' . rawurlencode($apiToken),
        ];
    }

    /**
     * Fetches a Trello collection and preserves API errors for remote selects.
     */
    private function getCollection(string $url, string $context): array
    {
        $response = wp_remote_get($url, ['timeout' => 30]);

        if (is_wp_error($response)) {
            return [
                'success' => false,
                'message' => $response->get_error_message(),
                'data'    => [],
            ];
        }

        $code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);

        if ($code < 200 || $code >= 300) {
            $message = is_array($data) ? ($data['message'] ?? $data['error'] ?? '') : '';
            $message = $message ?: trim($body) ?: 'Unknown error';

            return [
                'success' => false,
                'message' => 'Trello API error while ' . $context . ': ' . $message,
                'data'    => [],
            ];
        }

        if (!is_array($data)) {
            return [
                'success' => false,
                'message' => 'Invalid Trello API response while ' . $context,
                'data'    => [],
            ];
        }

        return [
            'success' => true,
            'message' => '',
            'data'    => $data,
        ];
    }

    /**
     * Returns open boards for the authenticated Trello user.
     */
    private function fetchBoards(string $authQuery): array
    {
        $url = 'https://api.trello.com/1/members/me/boards?fields=name,closed&filter=open&' . $authQuery;

        return $this->getCollection($url, 'fetching boards');
    }

    /**
     * Returns open lists for a Trello board.
     */
    private function fetchLists(string $boardId, string $authQuery): array
    {
        $url = 'https://api.trello.com/1/boards/' . rawurlencode($boardId) . '/lists?fields=name&filter=open&' . $authQuery;

        return $this->getCollection($url, 'fetching lists');
    }

    /**
     * Returns cards for a Trello list.
     */
    private function fetchCards(string $listId, string $authQuery): array
    {
        $url = 'https://api.trello.com/1/lists/' . rawurlencode($listId) . '/cards?fields=id,name&' . $authQuery;

        return $this->getCollection($url, 'fetching cards');
    }

    /**
     * Returns labels for a Trello board.
     */
    private function fetchLabels(string $boardId, string $authQuery): array
    {
        $url = 'https://api.trello.com/1/boards/' . rawurlencode($boardId) . '/labels?' . $authQuery;

        return $this->getCollection($url, 'fetching labels');
    }

    /**
     * Returns all boards accessible by the authenticated user.
     */
    public function boards(Request $request): Response
    {
        $connectionId = (int) $request->get('connection_id');
        if (!$connectionId) {
            return Response::error('Connection ID required', 400);
        }

        $auth = $this->buildAuth($connectionId);
        if (empty($auth)) {
            return Response::error('Invalid connection', 401);
        }

        $boards = $this->fetchBoards($auth['auth']);
        if (!$boards['success']) {
            return Response::error($boards['message'], 500);
        }

        $items = [];

        foreach ($boards['data'] as $board) {
            $items[] = [
                'value' => $board['id'],
                'label' => $board['name'],
            ];
        }

        return Response::success(['boards' => $items]);
    }

    /**
     * Returns all lists for a given board.
     */
    public function lists(Request $request): Response
    {
        $connectionId = (int) $request->get('connection_id');
        if (!$connectionId) {
            return Response::error('Connection ID required', 400);
        }

        $boardId = $request->get('board_id');
        if (!$boardId) {
            return Response::error('Board ID required', 400);
        }

        $auth = $this->buildAuth($connectionId);
        if (empty($auth)) {
            return Response::error('Invalid connection', 401);
        }

        $lists = $this->fetchLists($boardId, $auth['auth']);
        if (!$lists['success']) {
            return Response::error($lists['message'], 500);
        }

        $items = [];

        foreach ($lists['data'] as $list) {
            $items[] = [
                'value' => $list['id'],
                'label' => $list['name'],
            ];
        }

        return Response::success(['lists' => $items]);
    }

    /**
     * Returns cards for a list, or all accessible open-board cards when no list is selected.
     */
    public function cards(Request $request): Response
    {
        $connectionId = (int) $request->get('connection_id');
        if (!$connectionId) {
            return Response::error('Connection ID required', 400);
        }

        $auth = $this->buildAuth($connectionId);
        if (empty($auth)) {
            return Response::error('Invalid connection', 401);
        }

        $listId = (string) $request->get('list_id');
        if ($listId) {
            $cards = $this->fetchCards($listId, $auth['auth']);
            if (!$cards['success']) {
                return Response::error($cards['message'], 500);
            }

            $items = [];
            foreach ($cards['data'] as $card) {
                $items[] = [
                    'value' => $card['id'],
                    'label' => $card['name'],
                ];
            }

            return Response::success(['cards' => $items]);
        }

        $boards = $this->fetchBoards($auth['auth']);
        if (!$boards['success']) {
            return Response::error($boards['message'], 500);
        }

        $items = [];
        $limit = 500;

        foreach ($boards['data'] as $board) {
            $lists = $this->fetchLists((string) $board['id'], $auth['auth']);
            if (!$lists['success']) {
                return Response::error($lists['message'], 500);
            }

            foreach ($lists['data'] as $list) {
                $cards = $this->fetchCards((string) $list['id'], $auth['auth']);
                if (!$cards['success']) {
                    return Response::error($cards['message'], 500);
                }

                foreach ($cards['data'] as $card) {
                    $items[] = [
                        'value' => $card['id'],
                        'label' => $board['name'] . ' / ' . $list['name'] . ' / ' . $card['name'],
                    ];

                    if (count($items) >= $limit) {
                        break 3;
                    }
                }
            }
        }

        return Response::success(['cards' => $items]);
    }

    /**
     * Returns all members for a given board.
     */
    public function members(Request $request): Response
    {
        $connectionId = (int) $request->get('connection_id');
        if (!$connectionId) {
            return Response::error('Connection ID required', 400);
        }

        $boardId = (string) $request->get('board_id');
        if (!$boardId) {
            return Response::error('Board ID required', 400);
        }

        $auth = $this->buildAuth($connectionId);
        if (empty($auth)) {
            return Response::error('Invalid connection', 401);
        }

        $url     = 'https://api.trello.com/1/boards/' . rawurlencode($boardId) . '/members?fields=id,fullName&' . $auth['auth'];
        $members = $this->getCollection($url, 'fetching members');
        if (!$members['success']) {
            return Response::error($members['message'], 500);
        }

        $items = [];

        foreach ($members['data'] as $member) {
            $items[] = [
                'value' => $member['id'],
                'label' => $member['fullName'],
            ];
        }

        return Response::success(['members' => $items]);
    }

    /**
     * Returns labels for a board, or all accessible open-board labels when no board is selected.
     */
    public function labels(Request $request): Response
    {
        $connectionId = (int) $request->get('connection_id');
        if (!$connectionId) {
            return Response::error('Connection ID required', 400);
        }

        $auth = $this->buildAuth($connectionId);
        if (empty($auth)) {
            return Response::error('Invalid connection', 401);
        }

        $boardId = (string) $request->get('board_id');
        if ($boardId) {
            $labels = $this->fetchLabels($boardId, $auth['auth']);
            if (!$labels['success']) {
                return Response::error($labels['message'], 500);
            }

            $items = [];
            foreach ($labels['data'] as $label) {
                $labelName = $label['name'] ?: ($label['color'] ?: 'No color');
                $items[] = [
                    'value' => $label['id'],
                    'label' => $labelName,
                ];
            }

            return Response::success(['labels' => $items]);
        }

        $boards = $this->fetchBoards($auth['auth']);
        if (!$boards['success']) {
            return Response::error($boards['message'], 500);
        }

        $items = [];

        foreach ($boards['data'] as $board) {
            $labels = $this->fetchLabels((string) $board['id'], $auth['auth']);
            if (!$labels['success']) {
                return Response::error($labels['message'], 500);
            }

            foreach ($labels['data'] as $label) {
                $labelName = $label['name'] ?: ($label['color'] ?: 'No color');
                $items[] = [
                    'value' => $label['id'],
                    'label' => $board['name'] . ' / ' . $labelName,
                ];
            }
        }

        return Response::success(['labels' => $items]);
    }
}
