<?php

namespace GeminiLabs\SiteReviews\Integrations\Breakdance;

use Breakdance\Elements\PresetSections\PresetSectionsController;
use GeminiLabs\SiteReviews\Contracts\ShortcodeContract;
use GeminiLabs\SiteReviews\Controllers\AbstractController;
use GeminiLabs\SiteReviews\Database\ShortcodeOptionManager;
use GeminiLabs\SiteReviews\Helpers\Arr;
use GeminiLabs\SiteReviews\Helpers\Str;
use GeminiLabs\SiteReviews\Helpers\Svg;

use function Breakdance\Elements\PresetSections\getPresetSection;

class Controller extends AbstractController
{
    /**
     * @filter site-reviews/modal_wrapped_by
     */
    public function filterModalWrappedBy(array $builders): array
    {
        $builders[] = 'breakdance';
        return $builders;
    }

    /**
     * @filter site-reviews/breakdance/design_controls
     */
    public function filterTransformedDesignControls(array $controls, ShortcodeContract $shortcode): array
    {
        if ('site_reviews' === $shortcode->tag) {
            if (isset(PresetSectionsController::getInstance()->presets['GLSR\ButtonDesign'])) {
                $controls[] = getPresetSection('GLSR\ButtonDesign', 'Load More Button', 'load_more_button', [
                    'type' => 'popout',
                ]);
            }
        }
        if ('site_reviews_form' === $shortcode->tag) {
            if (isset(PresetSectionsController::getInstance()->presets['GLSR\FormDesign'])) {
                $controls[] = getPresetSection('GLSR\FormDesign', 'Form', 'form', [
                    'type' => 'popout',
                ]);
            }
        }
        return $controls;
    }

    /**
     * Breakdance does not provide a way to create a multi-select dropdown
     * populated by an AJAX callback on init AND search. To get around this,
     * we use the post_chooser control and override the callback with our own.
     *
     * @action breakdance_ajax_breakdance_get_posts:1
     * @action wp_ajax_breakdance_get_posts:1
     * @action wp_ajax_nopriv_breakdance_get_posts:1
     */
    public function interceptGetPostsQuery(): void
    {
        if (!$this->verifyRequest()) {
            return;
        }
        $pseudoPostTypeMap = [
            'assigned_posts' => 'assigned_posts',
            'assigned_terms' => 'assigned_terms',
            'assigned_users' => 'assigned_users',
            'review_authors' => 'author',
        ];
        $option = (string) filter_input(INPUT_POST, 'postType');
        $option = $pseudoPostTypeMap[$option] ?? Str::removePrefix($option, glsr()->prefix);
        $search = filter_input(INPUT_POST, 'search');
        $results = glsr(ShortcodeOptionManager::class)->get($option, compact('search'));
        $replacements = [ // the post_chooser control requires integer keys
            'post_id' => -10,
            'parent_id' => -20,
            'user_id' => -30,
            'author_id' => -40,
            'profile_id' => -50,
        ];
        if (in_array($option, ['assigned_posts'])) {
            $thumbnailFn = fn ($id) => get_the_post_thumbnail_url($id, 'thumbnail');
        } elseif (in_array($option, ['assigned_users', 'author'])) {
            $thumbnailFn = fn ($id) => get_avatar_url($id);
        }
        $data = $this->prepareResponse($results, $thumbnailFn ?? null, $replacements);
        if (in_array($option, ['post_id'])) {
            array_walk($data, function (&$item) {
                $item['title'] = "{$item['id']}: {$item['title']}";
            });
        }
        wp_send_json_success($data, 200);
        exit; // @phpstan-ignore-line
    }

    /**
     * @action unofficial_i_am_kevin_geary_master_of_all_things_css_and_html
     */
    public function printInlineStyles(): void
    {
        $icon = Svg::encoded('assets/images/icon-static.svg');
        echo '<style>'.
            '.breakdance-control-wrapper:has(+ .breakdance-control-wrapper [data-test-id$="_description_alert"] .breakdance-alert-box) {'.
                'margin-bottom: 7px;'.
            '}'.
            '[data-test-id$="_description_alert"] .breakdance-alert-box {'.
                'padding-inline: 13px;',
                '.v-alert__border--left {'.
                    'display: none;'.
                '}',
            '}',
            '.breakdance-add-panel__element:has(.glsr-icon) .breakdance-element-badge {'.
                'padding: 0;'.
                '&::after {'.
                    'background-image: url("'.$icon.'");'.
                    'content: "";'.
                    'height: var(--text-lg);'.
                    'width: var(--text-lg);'.
                '}'.
            '}'.
        '</style>';
    }

    /**
     * Breakdance loads an element by filtering the result of get_declared_classes
     * and checking if the class is_subclass_of \Breakdance\Elements\Element.
     *
     * Controls are added dynamically from the Shortcode class to enforce consistancy
     * across builder integrations. As a result, we need to bypass the Element Studio
     * and we do this by setting the save location to $onlyForAdvancedUsers and
     * $excludeFromElementStudio.
     *
     * @action breakdance_loaded:5
     */
    public function registerElements(): void
    {
        $pluginDir = dirname(plugin_basename(glsr()->file));
        \Breakdance\Elements\registerCategory(glsr()->id, glsr()->name);
        \Breakdance\ElementStudio\registerSaveLocation(
            "{$pluginDir}/assets/breakdance/elements",
            'GLSR_Breakdance',
            'element',
            'Site Reviews Elements',
            true, // onlyForAdvancedUsers
            true // excludeFromElementStudio
        );
        \Breakdance\ElementStudio\registerSaveLocation(
            "{$pluginDir}/assets/breakdance/macros",
            'GLSR_Breakdance',
            'macro',
            'Site Reviews Macros',
            true, // onlyForAdvancedUsers
            true // excludeFromElementStudio
        );
        \Breakdance\ElementStudio\registerSaveLocation(
            "{$pluginDir}/assets/breakdance/presets",
            'GLSR_Breakdance',
            'preset',
            'Site Reviews Presets',
            true, // onlyForAdvancedUsers
            true // excludeFromElementStudio
        );
    }

    /**
     * @action init
     */
    public function registerPresets(): void
    {
        $presets = [
            'GLSR\ButtonDesign' => glsr()->path('assets/breakdance/presets/button-design.php'),
            'GLSR\FormDesign' => glsr()->path('assets/breakdance/presets/form-design.php'),
        ];
        $presets = glsr()->filterArray('breakdance/presets', $presets);
        foreach ($presets as $presetName => $presetPath) {
            if (file_exists($presetPath)) {
                $controls = include $presetPath;
                PresetSectionsController::getInstance()->register($presetName, $controls, true);
            }
        }
    }

    /**
     * Unfortunately we can't use this yet because Breakdance does not support
     * AJAX searching in multiselect controls.
     *
     * @action breakdance_loaded
     */
    public function registerRoutes(): void
    {
        return; // We can't use this yet...
        // $input = filter_input_array(INPUT_POST, [ // @phpstan-ignore-line
        //     'requestData' => [
        //         'context' => [
        //             'filter' => fn ($value) => is_numeric($value)
        //                 ? intval($value)
        //                 : strip_tags($value),
        //             'flags' => FILTER_REQUIRE_ARRAY,
        //         ],
        //     ],
        // ]);
        // $include = Arr::consolidate($input['requestData']['context'] ?? []);
        // \Breakdance\AJAX\register_handler(
        //     glsr()->prefix.'breakdance_assigned_posts',
        //     fn () => $this->fetchAssignedPosts($include),
        //     'edit'
        // );
        // \Breakdance\AJAX\register_handler(
        //     glsr()->prefix.'breakdance_assigned_terms',
        //     fn () => $this->fetchAssignedTerms($include),
        //     'edit'
        // );
        // \Breakdance\AJAX\register_handler(
        //     glsr()->prefix.'breakdance_assigned_users',
        //     fn () => $this->fetchAssignedUsers($include),
        //     'edit'
        // );
        // \Breakdance\AJAX\register_handler(
        //     glsr()->prefix.'breakdance_author',
        //     fn () => $this->fetchAuthor($include),
        //     'edit'
        // );
        // \Breakdance\AJAX\register_handler(
        //     glsr()->prefix.'breakdance_post_id',
        //     fn () => $this->fetchPostId($include),
        //     'edit'
        // );
    }

    /**
     * Unfortunately we can't use this yet because Breakdance does not support
     * AJAX searching in multiselect controls.
     */
    protected function fetchAssignedPosts(array $include): array
    {
        // $include = array_filter($include, fn ($id) => is_numeric($id) || in_array($id, [
        //     'parent_id',
        //     'post_id',
        // ]));
        return [];
    }

    /**
     * Unfortunately we can't use this yet because Breakdance does not support
     * AJAX searching in multiselect controls.
     */
    protected function fetchAssignedTerms(array $include): array
    {
        return [];
    }

    /**
     * Unfortunately we can't use this yet because Breakdance does not support
     * AJAX searching in multiselect controls.
     */
    protected function fetchAssignedUsers(array $include): array
    {
        // $include = array_filter($include, fn ($id) => is_numeric($id) || in_array($id, [
        //     'author_id',
        //     'profile_id',
        //     'user_id',
        // ]));
        return [];
    }

    /**
     * Unfortunately we can't use this yet because Breakdance does not support
     * AJAX searching in multiselect controls.
     */
    protected function fetchAuthor(array $include): array
    {
        // $include = array_filter($include, fn ($id) => is_numeric($id) || in_array($id, [
        //     'user_id',
        // ]));
        return [];
    }

    /**
     * Unfortunately we can't use this yet because Breakdance does not support
     * AJAX searching in multiselect controls.
     */
    protected function fetchPostId(array $include): array
    {
        return [];
    }

    protected function prepareResponse(array $results, ?callable $thumbnailFn = null, array $replacements = []): array
    {
        if (!$thumbnailFn) {
            $thumbnailFn = fn () => false;
        }
        $callback = fn ($id, $title) => [
            'id' => $replacements[$id] ?? $id,
            'title' => $title,
            'thumbnail' => $thumbnailFn($id),
        ];
        return array_map($callback, array_keys($results), $results);
    }

    protected function verifyRequest(): bool
    {
        $checkFor = [
            glsr()->prefix,
            'assigned_posts',
            'assigned_terms',
            'assigned_users',
            'review_authors',
        ];
        $postType = filter_input(INPUT_POST, 'postType');
        if (empty(array_filter($checkFor, fn ($prefix) => str_starts_with($postType, $prefix)))) {
            return false;
        }
        if (!\Breakdance\Permissions\hasMinimumPermission('edit')) {
            return false;
        }
        $nonceTick = check_ajax_referer(\Breakdance\AJAX\get_nonce_key_for_ajax_requests(), false, false);
        if (!$nonceTick) {
            return false;
        }
        if (2 === $nonceTick) {
            $refreshNonce = \Breakdance\AJAX\get_nonce_for_ajax_requests();
            header('Breakdance-Refresh-Nonce:'.$refreshNonce);
        }
        return true;
    }
}
