<?php

declare(strict_types=1);

namespace CliqThemes\StoreLocator\REST;

defined('ABSPATH') || exit;

use CliqThemes\StoreLocator\Support\SettingsService;
use WP_REST_Request;
use WP_REST_Response;

/**
 * Settings endpoint for the Store Locator admin screen.
 *
 * The key list is the endpoint's schema: it is enforced server-side so a
 * request can only write settings this plugin defines, whatever the browser
 * sends.
 */
final class SettingsController
{
    /** @var string[] */
    private const KEYS = [
        'map_provider',
        'google_maps_api_key',
        'google_maps_api_loaded_externally',
        'google_server_api_key',
        'geocoder',
        'map_default_lat',
        'map_default_lng',
        'map_default_zoom',
        'search_zoom',
        'clicked_zoom',
        'map_type',
        'map_style',
        'enable_clustering',
        'distance_unit',
        'restrict_country',
        'enable_autocomplete',
        'theme_primary',
        'theme_primary_strong',
        'theme_on_primary',
        'theme_canvas',
        'theme_surface',
        'theme_text',
        'theme_heading',
        'theme_text_soft',
        'theme_label',
        'theme_muted',
        'theme_faint',
        'theme_border',
        'theme_border_soft',
        'theme_divider',
        'theme_danger',
        'theme_danger_bg',
        'store_detail_pages',
        'store_detail_page',
        'store_detail_slug_fields',
        'locator_map_position',
        'locator_map_columns',
        'locator_list_columns',
        'locator_list_min_width',
        'locator_map_height',
        'locator_results_per_page',
        'locator_show_load_more',
        'locator_load_more_label',
        'locator_phone_label',
        'locator_email_label',
        'locator_website_label',
        'locator_directions_button_label',
        'locator_details_button_label',
        'locator_location_label',
        'locator_location_placeholder',
        'locator_category_label',
        'locator_distance_label',
        'locator_search_button_label',
        'locator_result_count_label',
        'locator_empty_results_message',
        'locator_show_search',
        'locator_show_category_filter',
        'locator_show_radius_filter',
        'locator_show_result_count',
        'locator_show_print',
        'locator_detail_show_hero',
        'locator_card_fields',
        'locator_card_columns',
        'locator_infobox_fields',
        'locator_detail_fields',
        'locator_detail_columns',
        'locator_enable_clustering',
        'locator_default_zoom',
        'locator_marker_preset',
    ];

    public function register(): void
    {
        add_action('rest_api_init', [$this, 'registerRoutes']);
    }

    public function registerRoutes(): void
    {
        $permission = [$this, 'permission'];
        register_rest_route(AdminController::NAMESPACE, '/admin/settings', [
            [
                'methods' => 'GET',
                'callback' => [$this, 'get'],
                'permission_callback' => $permission,
            ],
            [
                'methods' => 'POST',
                'callback' => [$this, 'update'],
                'permission_callback' => $permission,
            ],
        ]);
    }

    public function permission(): bool
    {
        return current_user_can('manage_store_locator') || current_user_can('manage_options');
    }

    public function get(): WP_REST_Response
    {
        return new WP_REST_Response([
            'settings' => $this->onlyAllowed(SettingsService::allMasked()),
            'defaults' => $this->onlyAllowed(SettingsService::defaults()),
        ]);
    }

    public function update(WP_REST_Request $request): WP_REST_Response
    {
        $body = $request->get_json_params();
        if (! is_array($body)) {
            $body = $request->get_params();
        }

        $submitted = is_array($body) ? $this->onlyAllowed($body) : [];
        SettingsService::update($submitted);

        return new WP_REST_Response(['settings' => $this->onlyAllowed(SettingsService::allMasked())]);
    }

    /**
     * @param array<string, mixed> $values
     *
     * @return array<string, mixed>
     */
    private function onlyAllowed(array $values): array
    {
        return array_intersect_key($values, array_fill_keys(self::KEYS, true));
    }
}
