<?php

declare(strict_types=1);

namespace PrettyLinks\Pro\Blocks;

defined('ABSPATH') || exit;

use PrettyLinks\Admin\Assets as LiteAdminAssets;

// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
// phpcs:disable WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key
// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_value
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter
// Custom plugin tables (prli_*): table names interpolated from $wpdb->prefix (trusted),
// user values bind through $wpdb->prepare(). No caching: these tables are the source
// of truth for click/redirect data and must read-through. "meta_key"/"meta_value" here
// refer to our own prli_link_metas table, not wp_postmeta.

/**
 * Registers the Pretty Link pixel block, its REST query filters, and the
 * `pretty_link_pixel` shortcode.
 */
class PixelBlock
{
    /**
     * Register the block, REST filters, asset hooks, and shortcode.
     *
     * @return void
     */
    public function register(): void
    {
        add_filter('prli_links_index_args', [$this, 'injectRedirectTypeArg'], 10, 2);
        add_filter('prli_links_query_clauses', [$this, 'applyRedirectTypeClause'], 10, 2);
        add_action('init', [$this, 'registerBlock']);
        // The block's editor bundle imports from `@shared` (resolves to
        // `window.prli.shared`), so the `prli-shared` handle MUST be
        // registered before WP's `wp_enqueue_registered_block_scripts_and_styles`
        // (hooked at `enqueue_block_editor_assets` priority 10 — see
        // wp-includes/default-filters.php) tries to enqueue the
        // pixel-block editor script and resolves its `prli-shared` dep.
        // Priority 1 ensures Lite's shared library is registered first,
        // otherwise WP fires "enqueued with dependencies that are not
        // registered" and skips loading prli-shared.
        add_action('enqueue_block_editor_assets', [LiteAdminAssets::class, 'enqueueSharedLibrary'], 1);
        add_shortcode('pretty_link_pixel', [$this, 'renderShortcode']);
    }

    /**
     * Inject the `redirect_type` filter into the links index query args.
     *
     * @param array<string, mixed> $args    The accumulated query args.
     * @param \WP_REST_Request     $request The incoming REST request.
     *
     * @return array<string, mixed> The query args with redirect_type applied.
     */
    public function injectRedirectTypeArg(array $args, \WP_REST_Request $request): array
    {
        $rt = $request->get_param('redirect_type');
        if ($rt !== null && $rt !== '') {
            $args['redirect_type'] = sanitize_key((string) $rt);
        }
        return $args;
    }

    /**
     * Apply a `redirect_type` WHERE clause to the links query.
     *
     * @param array{0: array<int, string>, 1: array<int, mixed>} $clauses The accumulated WHERE clause parts and params.
     * @param array<string, mixed>                               $args    The links query arguments.
     *
     * @return array{0: array<int, string>, 1: array<int, mixed>} The updated clauses.
     */
    public function applyRedirectTypeClause(array $clauses, array $args): array
    {
        if (empty($args['redirect_type'])) {
            return $clauses;
        }
        [$where, $params] = $clauses;
        $where[]          = 'redirect_type = %s';
        $params[]         = $args['redirect_type'];
        return [$where, $params];
    }

    /**
     * Register the pixel block type and its editor assets.
     *
     * @return void
     */
    public function registerBlock(): void
    {
        $assetFile = PRLI_PATH . 'pro/assets/js/build/pixel-block.asset.php';
        $asset     = file_exists($assetFile) ? (array) require $assetFile : [
            'dependencies' => [],
            'version'      => '1',
        ];

        // Register `prli-shared` here too (not just via the
        // enqueue_block_editor_assets hook) so the handle exists at the
        // moment WP enqueues this editor script. Otherwise WP fires
        // "enqueued with dependencies that are not registered" because
        // `wp_enqueue_registered_block_scripts_and_styles` (priority 10)
        // can run before any other action callback registers the lib.
        // wp_register_script is idempotent: if Lite already registered
        // the handle, this is a no-op.
        if (!wp_script_is(LiteAdminAssets::SHARED_HANDLE, 'registered')) {
            $sharedAssetFile = PRLI_PATH . 'assets/js/build/shared.asset.php';
            $sharedAsset     = file_exists($sharedAssetFile)
                ? (array) require $sharedAssetFile
                : [
                    'dependencies' => ['wp-element', 'wp-components', 'wp-i18n', 'wp-api-fetch', 'wp-data'],
                    'version'      => '1',
                ];
            wp_register_script(
                LiteAdminAssets::SHARED_HANDLE,
                PRLI_URL . 'assets/js/build/shared.js',
                (array) ($sharedAsset['dependencies'] ?? []),
                (string) ($sharedAsset['version'] ?? '1'),
                true
            );
            wp_set_script_translations(LiteAdminAssets::SHARED_HANDLE, 'pretty-link');
        }
        if (!wp_style_is(LiteAdminAssets::SHARED_HANDLE, 'registered')) {
            $sharedAssetFile = PRLI_PATH . 'assets/js/build/shared.asset.php';
            $sharedAsset     = file_exists($sharedAssetFile)
                ? (array) require $sharedAssetFile
                : ['version' => '1'];
            wp_register_style(
                LiteAdminAssets::SHARED_HANDLE,
                PRLI_URL . 'assets/css/build/shared.css',
                ['wp-components'],
                (string) ($sharedAsset['version'] ?? '1')
            );
        }

        // The .asset.php emitted by @wordpress/scripts only sees imports
        // resolvable to npm packages — the `@shared` external never makes
        // it in there. Add it explicitly so WP guarantees prli-shared
        // loads (and runs) before the block's editor JS executes.
        $deps = (array) ($asset['dependencies'] ?? []);
        if (!in_array(LiteAdminAssets::SHARED_HANDLE, $deps, true)) {
            $deps[] = LiteAdminAssets::SHARED_HANDLE;
        }

        wp_register_script(
            'pretty-links-pixel-block-editor',
            PRLI_URL . 'pro/assets/js/build/pixel-block.js',
            $deps,
            (string) ($asset['version'] ?? '1'),
            true
        );
        wp_set_script_translations('pretty-links-pixel-block-editor', 'pretty-link-pro');

        wp_register_style(
            'pretty-links-pixel-block-editor-style',
            PRLI_URL . 'pro/assets/css/build/pixel-block.css',
            [],
            (string) ($asset['version'] ?? '1')
        );

        register_block_type(
            PRLI_PATH . 'pro/assets/blocks/pixel-block',
            ['render_callback' => [$this, 'render']]
        );
    }

    /**
     * Render the `[pretty_link_pixel id="123"]` / `slug="my-link"` shortcode.
     *
     * @param array<string, mixed> $atts The shortcode attributes.
     *
     * @return string The tracking pixel HTML, or empty string when not found.
     */
    public function renderShortcode(array $atts): string
    {
        $atts = shortcode_atts([
            'id'   => 0,
            'slug' => '',
        ], $atts, 'pretty_link_pixel');

        global $wpdb;

        if (!empty($atts['slug'])) {
            $row = $wpdb->get_row(
                $wpdb->prepare(
                    "SELECT slug FROM {$wpdb->prefix}prli_links WHERE slug = %s AND redirect_type = 'pixel' AND deleted_at IS NULL LIMIT 1",
                    sanitize_text_field((string) $atts['slug'])
                ),
                ARRAY_A
            );
        } else {
            $linkId = (int) $atts['id'];
            if ($linkId <= 0) {
                return '';
            }
            $row = $wpdb->get_row(
                $wpdb->prepare(
                    "SELECT slug FROM {$wpdb->prefix}prli_links WHERE id = %d AND redirect_type = 'pixel' AND deleted_at IS NULL LIMIT 1",
                    $linkId
                ),
                ARRAY_A
            );
        }

        if (!$row) {
            return '';
        }

        $url = \PrettyLinks\Helpers\LinkUrl::build((string) $row['slug']);

        return sprintf(
            '<img src="%s" class="pretty-link pretty-link-tracking-pixel" width="1" height="1" style="display:none!important" alt="" />',
            esc_url($url)
        );
    }

    /**
     * Render the pixel block from its saved attributes.
     *
     * @param array<string, mixed> $attributes The block attributes.
     *
     * @return string The tracking pixel HTML, or empty string when not found.
     */
    public function render(array $attributes): string
    {
        $linkId = (int) ($attributes['linkId'] ?? 0);
        if ($linkId <= 0) {
            return '';
        }

        global $wpdb;
        $row = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT slug FROM {$wpdb->prefix}prli_links WHERE id = %d AND redirect_type = 'pixel' AND deleted_at IS NULL LIMIT 1",
                $linkId
            ),
            ARRAY_A
        );

        if (!$row) {
            return '';
        }

        $url = \PrettyLinks\Helpers\LinkUrl::build((string) $row['slug']);

        return sprintf(
            '<img src="%s" class="pretty-link pretty-link-tracking-pixel" width="1" height="1" style="display:none!important" alt="" />',
            esc_url($url)
        );
    }
}
