<?php

declare(strict_types=1);

namespace PrettyLinks\Pro\Rest;

use PrettyLinks\Pro\Tools\Bookmarklet;
use PrettyLinks\Rest\Controllers\BaseController;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

class BookmarkletController extends BaseController
{
    /**
     * Register the bookmarklet REST routes.
     *
     * @return void
     */
    public function register(): void
    {
        $categoryIdsArg = [
            'type'    => 'array',
            'items'   => ['type' => 'integer'],
            'default' => [],
        ];

        register_rest_route($this->namespace(), '/tools/bookmarklet', [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [$this, 'show'],
                'permission_callback' => $this->permission(),
                'args'                => [
                    'category_ids' => $categoryIdsArg,
                ],
            ],
        ]);

        register_rest_route($this->namespace(), '/tools/bookmarklet/regenerate', [
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [$this, 'regenerate'],
                'permission_callback' => $this->permission(),
                'args'                => [
                    'category_ids' => $categoryIdsArg,
                ],
            ],
        ]);
    }

    /**
     * Return the current bookmarklet token and payload.
     *
     * @param WP_REST_Request $request Incoming REST request.
     *
     * @return WP_REST_Response
     */
    public function show(WP_REST_Request $request): WP_REST_Response
    {
        $token = Bookmarklet::getOrCreateToken();
        return new WP_REST_Response($this->shape($token, self::normalizeCategoryIds($request)));
    }

    /**
     * Regenerate the bookmarklet token and return the new payload.
     *
     * @param WP_REST_Request $request Incoming REST request.
     *
     * @return WP_REST_Response
     */
    public function regenerate(WP_REST_Request $request): WP_REST_Response
    {
        $token = Bookmarklet::regenerateToken();
        return new WP_REST_Response($this->shape($token, self::normalizeCategoryIds($request)));
    }

    /**
     * Build the bookmarklet response payload.
     *
     * @param string $token       Bookmarklet auth token.
     * @param int[]  $categoryIds Category ids to bind into the bookmarklet.
     *
     * @return array<string, mixed>
     */
    private function shape(string $token, array $categoryIds = []): array
    {
        $endpointUrl = home_url('/?' . Bookmarklet::ENDPOINT_QUERY_VAR . '=');

        $extraParams = [];
        if ($categoryIds !== []) {
            $extraParams['category_ids'] = $categoryIds;
        }

        return [
            'token'        => $token,
            'endpoint_url' => $endpointUrl,
            'category_ids' => $categoryIds,
            'payload'      => Bookmarklet::payload($endpointUrl, $token, $extraParams),
        ];
    }

    /**
     * Extract and de-duplicate positive category ids from the request.
     *
     * @param WP_REST_Request $request Incoming REST request.
     *
     * @return int[]
     */
    private static function normalizeCategoryIds(WP_REST_Request $request): array
    {
        $raw = (array) $request->get_param('category_ids');
        $ids = [];
        foreach ($raw as $val) {
            $id = (int) $val;
            if ($id > 0 && !in_array($id, $ids, true)) {
                $ids[] = $id;
            }
        }
        return $ids;
    }
}
