<?php

namespace SoftminalB2B\Http\Controllers;

if (!defined('ABSPATH')) {
    exit;
}

use SoftminalB2B\Registration\RegistrationForm;
use SoftminalB2B\Services\Settings;
use SoftminalB2B\Support\Tier;

/**
 * Shop-wide B2B settings. Only keys declared in Settings::$defaults can be
 * written, so a stray field in a request can never create an option.
 */
class SettingsController extends Controller
{
    /**
     * Which settings the admin screen may read and write, and how each one is
     * cleaned. Anything absent here is invisible to the API.
     */
    private const EDITABLE = [
        'hide_prices_for_guests'      => 'bool',
        'hide_add_to_cart_for_guests' => 'bool',
        'hide_prices_message'         => 'html',
        'registration_enabled'        => 'bool',
        'registration_auto_approve'   => 'bool',
        'registration_default_group'  => 'int',
        'price_display_suffix'        => 'text',
        'show_savings_badge'          => 'bool',
        'tax_toggle_enabled'          => 'bool',
        'bulk_order_page_size'        => 'int',
        'bulk_order_show_thumbnails'  => 'bool',
        'bulk_order_show_sku'         => 'bool',
        'bulk_order_show_categories'  => 'bool',
        'bulk_order_show_savings'     => 'bool',
        'bulk_order_enable_paste'     => 'bool',
        'bulk_order_enable_lists'     => 'bool',
        'bulk_order_density'          => 'text',
        'bulk_order_pager_align'      => 'text',
        'bulk_order_sticky_bar'       => 'bool',
        'bulk_order_hide_oos'         => 'bool',
        'bulk_order_intro'            => 'html',
        'bulk_order_accent'           => 'color',
        'remove_data_on_uninstall'    => 'bool',
        'remove_financial_data'       => 'bool',

        // PDF invoices (G4)
        'invoices_enabled'            => 'bool',
        'invoice_template'            => 'text',
        'invoice_business_name'       => 'text',
        'invoice_business_address'    => 'textarea',
        'invoice_business_vat'        => 'text',
        'invoice_business_email'      => 'email',
        'invoice_footer_note'         => 'textarea',
        'invoice_logo_id'             => 'int',
    ];

    /**
     * The editable settings map (key => type). Pro modules register their own
     * keys through the filter, so their settings save through this one endpoint
     * rather than each needing a bespoke route.
     *
     * @return array<string, string>
     */
    private function editable(): array
    {
        /**
         * Filter the settings the admin API will read and write.
         *
         * @param array<string, string> $editable key => type (bool|int|text|textarea|email|html)
         */
        return (array) apply_filters('smb2b_editable_settings', self::EDITABLE);
    }

    public function index(\WP_REST_Request $request, $params = [])
    {
        $settings = [];

        foreach ($this->editable() as $key => $type) {
            $settings[$key] = $this->present($key, $type);
        }

        return $this->success([
            'settings' => $settings,
            'tier'     => Tier::toArray(),
            // The registration form's shortcode, so the settings screen can show
            // merchants exactly what to paste onto a page. Sourced from the form
            // so it can never drift from the real handle.
            'registration_shortcode' => '[' . RegistrationForm::SHORTCODE . ']',
        ]);
    }

    public function update(\WP_REST_Request $request, $params = [])
    {
        $incoming = (array) $request->get_param('settings');
        $editable = $this->editable();
        $saved    = [];

        foreach ($incoming as $key => $value) {
            if (!isset($editable[$key])) {
                continue;
            }

            Settings::set($key, $this->sanitize($value, $editable[$key]));
            $saved[] = $key;
        }

        if (empty($saved)) {
            return $this->error(__('Nothing to save.', 'softminal-b2b-wholesale-for-woocommerce'), 422);
        }

        $settings = [];

        foreach ($this->editable() as $key => $type) {
            $settings[$key] = $this->present($key, $type);
        }

        return $this->success(
            ['settings' => $settings],
            __('Settings saved.', 'softminal-b2b-wholesale-for-woocommerce')
        );
    }

    /**
     * @return mixed
     */
    private function present(string $key, string $type)
    {
        $value = Settings::get($key);

        switch ($type) {
            case 'bool':
                return $value === 'yes';
            case 'int':
                return (int) $value;
            default:
                return (string) $value;
        }
    }

    /**
     * @param mixed $value
     * @return mixed
     */
    private function sanitize($value, string $type)
    {
        switch ($type) {
            case 'bool':
                // Stored as yes/no so the values stay readable in wp_options.
                return ($value === true || $value === 'yes' || $value === 1 || $value === '1') ? 'yes' : 'no';

            case 'int':
                return absint($value);

            case 'email':
                return sanitize_email((string) $value);

            case 'textarea':
                return sanitize_textarea_field((string) $value);

            case 'color':
                // A hex colour like #6D5EF5, or empty to fall back to the default.
                $color = sanitize_hex_color((string) $value);
                return $color ?: '';

            case 'html':
                // The hidden-price message is merchant-authored copy that may
                // legitimately contain a link, so post-level HTML is allowed.
                return wp_kses_post((string) $value);

            default:
                return sanitize_text_field((string) $value);
        }
    }
}
