<?php

declare(strict_types=1);

namespace PrettyLinks\Pro\Tools;

// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash
// phpcs:disable WordPress.Security.NonceVerification.Recommended
// $_SERVER values (REMOTE_ADDR, HTTP_USER_AGENT, REQUEST_URI, etc.) are read for
// click tracking / targeting / UI rendering, not form-submission input. State-changing
// operations in this class protect with wp_verify_nonce / check_admin_referer.
use PrettyLinks\Admin\Page;
use PrettyLinks\Admin\Pages\AddNew;
use PrettyLinks\Repositories\Links as LinksRepository;

class BookmarkletHandler
{
    /**
     * Links repository used to create links and assign terms.
     *
     * @var LinksRepository
     */
    private LinksRepository $links;

    /**
     * Constructor.
     *
     * @param LinksRepository $links Links repository dependency.
     */
    public function __construct(LinksRepository $links)
    {
        $this->links = $links;
    }

    /**
     * Handle an incoming bookmarklet request, creating a link when the token is valid.
     *
     * @return void
     */
    public function maybeHandle(): void
    {
        if (!isset($_REQUEST[Bookmarklet::ENDPOINT_QUERY_VAR])) {
            return;
        }

        $token = sanitize_text_field((string) wp_unslash($_REQUEST[Bookmarklet::ENDPOINT_QUERY_VAR]));
        if ($token === '' || !hash_equals(Bookmarklet::getOrCreateToken(), $token)) {
            wp_die(
                esc_html__('Invalid bookmarklet token.', 'pretty-link-pro'),
                esc_html__('Forbidden', 'pretty-link-pro'),
                ['response' => 403]
            );
        }

        if (!is_user_logged_in()) {
            // Resume the create after login: bounce to wp-login with a
            // redirect_to pointing back at this exact bookmarklet request, so
            // the token / target_url / name / category_ids all replay and the
            // link is created once the user authenticates.
            // Reconstruct the absolute current URL from the *configured* home
            // host + the raw REQUEST_URI. Taking only the host (not the path)
            // from home_url() avoids the subdirectory path doubling that
            // home_url($requestUri) would cause (REQUEST_URI already includes
            // the subdir), while keeping the host trusted rather than the
            // user-controlled Host header.
            $requestUri = isset($_SERVER['REQUEST_URI']) ? wp_unslash((string) $_SERVER['REQUEST_URI']) : '';
            $parsedHome = wp_parse_url(home_url());
            $host       = isset($parsedHome['host']) ? $parsedHome['host'] : '';
            $port       = isset($parsedHome['port']) ? ':' . $parsedHome['port'] : '';
            $currentUrl = $host !== ''
                ? set_url_scheme('http://' . $host . $port . $requestUri)
                : home_url($requestUri);
            wp_safe_redirect(wp_login_url(esc_url_raw($currentUrl)));
            exit;
        }

        if (!current_user_can(Page::capability())) {
            wp_die(
                esc_html__('You do not have permission to add Pretty Links.', 'pretty-link-pro'),
                esc_html__('Forbidden', 'pretty-link-pro'),
                ['response' => 403]
            );
        }

        $targetUrl = isset($_REQUEST['target_url'])
            ? esc_url_raw(wp_unslash((string) $_REQUEST['target_url']))
            : '';
        $name      = isset($_REQUEST['name'])
            ? sanitize_text_field(wp_unslash((string) $_REQUEST['name']))
            : '';

        $categoryIds = [];
        if (isset($_REQUEST['category_ids'])) {
            foreach ((array) wp_unslash($_REQUEST['category_ids']) as $rawId) {
                $id = (int) $rawId;
                if ($id > 0 && !in_array($id, $categoryIds, true)) {
                    $categoryIds[] = $id;
                }
            }
        }

        $result = $this->links->create([
            'url'  => $targetUrl,
            'name' => $name,
        ]);

        if (isset($result['error'])) {
            wp_die(
                esc_html(sprintf(
                    // phpcs:ignore Squiz.Commenting.InlineComment.NotCapital,Squiz.Commenting.InlineComment.InvalidEndChar -- translators comment must stay verbatim.
                    // translators: %s: error code from the Links repository
                    __('Could not create Pretty Link: %s', 'pretty-link-pro'),
                    (string) $result['error']
                )),
                esc_html__('Pretty Links Bookmarklet', 'pretty-link-pro'),
                [
                    'back_link' => true,
                    'response'  => 400,
                ]
            );
        }

        // Assign categories directly via the Lite repo — LinksRepository::create()
        // doesn't fire prli_link_after_save (that hook lives in REST controllers),
        // so Pro's LinkPayloadExtension won't pick up a `categories` payload field
        // on direct create() calls. Call setTerms explicitly instead.
        $linkId = (int) ($result['id'] ?? 0);
        if ($linkId > 0 && $categoryIds !== []) {
            $this->links->setTerms($linkId, 'category', $categoryIds);
        }

        // Land on the Add New screen's post-create confirmation (same screen
        // the in-admin create flow shows), which reads `created=<id>` and
        // renders the new pretty URL with copy/edit actions.
        wp_safe_redirect(add_query_arg(
            [
                'page'    => AddNew::SLUG,
                'created' => $linkId,
            ],
            admin_url('admin.php')
        ));
        exit;
    }
}
