<?php
/**
 * BookiFlex Core
 *
 * @package    BookiFlex
 * @subpackage Core
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Core\Admin\Settings;

use BookiFlex\Core\Contract\PluginInterface;
use BookiFlex\Core\Contract\RoleCapabilitiesInterface;

defined( 'ABSPATH' ) || exit;

/**
 * Main Settings Manager class.
 *
 * Provides both UI configuration (via Carbon Fields) and programmatic access to settings values.
 */
class SettingsManager
{
    // General settings
    public const CHECK_IN_TIME    = 'bflex__check_in_time';
    public const CHECK_OUT_TIME   = 'bflex__check_out_time';
    public const DEFAULT_CURRENCY = 'bflex__default_currency';
    public const WIDGET_LANGUAGE  = 'bflex__widget_language';

    // Auto confirmation settings
    public const AUTO_CONFIRMATION_FOR_NON_PAYABLE_PAYMENT_TYPES = 'bflex__auto_confirmation__non_payable';
    public const AUTO_CONFIRMATION_AFTER_PAYMENT_IS_PAID         = 'bflex__auto_confirmation__after_paid';

    // Contact and location
    public const NAME      = 'bflex__contact__name';
    public const ADDRESS   = 'bflex__contact__address';
    public const PHONE     = 'bflex__contact__phone';
    public const EMAIL     = 'bflex__contact__email';
    public const LONGITUDE = 'bflex__location__longitude';
    public const LATITUDE  = 'bflex__location__latitude';

    // Policies and agreements
    public const RULES_OF_LIVING = 'bflex__policy__rules_of_living';
    public const AGREEMENTS      = 'bflex__policy__agreements';

    // Payment
    public const BANK_ACCOUNT = 'bflex__payment__bank_account';

    // Children
    public const CHILD_AGE_PERIODS  = 'bflex__child_age_periods';
    public const CHILDREN_ENABLED   = 'bflex__children__enabled';
    public const CHILDREN_MAX_COUNT = 'bflex__children__max_count';

    // Widget button settings
    public const BOOKING_BUTTON_ACTIVE   = 'bflex__widget_button__active';
    public const BOOKING_BUTTON_TEXT     = 'bflex__widget_button__text';
    public const BOOKING_BUTTON_POSITION = 'bflex__widget_button__position';
    public const BOOKING_BUTTON_COLOR    = 'bflex__widget_button__color';
    public const BOOKING_BUTTON_PULSE    = 'bflex__widget_button__pulse';

    // Widget appearance
    public const WIDGET_CSS_TOKENS = 'bflex__widget__css_tokens';

    private array $containers = [];

    public function __construct(
        private readonly SettingsFieldsConfig $fieldsConfig,
        private readonly PluginInterface $plugin
    ) {
        $this->initializeDefaultSettings();
    }

    /**
     * Get setting value using Carbon Fields API.
     *
     * @param string $key Setting key (use class constants)
     * @param mixed $default Default value if setting doesn't exist
     * @return mixed Setting value
     */
    public function getValue(string $key, mixed $default = null): mixed
    {
        return carbon_get_theme_option($key) ?? $default;
    }

    /**
     * Set setting value using Carbon Fields API.
     *
     * Note: This only works after Carbon Fields is initialized.
     * For programmatic setting during activation/migration, use setValueDirect() instead.
     *
     * @param string $key Setting key (use class constants)
     * @param mixed $value Value to set
     * @return bool Success status
     */
    public function setValue(string $key, mixed $value): bool
    {
        carbon_set_theme_option($key, $value);
        return true;
    }

    /**
     * Set setting value directly using WordPress option API.
     *
     * Use when Carbon Fields context is uncertain (e.g., during migrations, activation, onboarding).
     * Carbon Fields adds '_' prefix internally to option keys in the database.
     *
     * @param string $key Setting key (use class constants)
     * @param mixed $value Value to set
     * @return bool Success status
     */
    public function setValueDirect(string $key, mixed $value): bool
    {
        return update_option('_' . $key, $value);
    }

    /**
     * Check if setting exists and has a non-null value.
     *
     * @param string $key Setting key
     * @return bool
     */
    public function has(string $key): bool
    {
        return carbon_get_theme_option($key) !== null;
    }

    /**
     * Initialize default settings container with tabs
     */
    private function initializeDefaultSettings(): void
    {
        $container = new SettingsContainer(
            'bflex__settings',
            __('Settings', 'bookiflex')
        );
        $container->setCapability(RoleCapabilitiesInterface::MANAGE_CONFIGURATION);

        // Add default tabs using SettingsFieldsConfig
        $container->addTab(
            (new SettingsTab('general', __('General', 'bookiflex')))
                ->addFieldsFactory($this->fieldsConfig->generalSettingsFactory())
        );

        $container->addTab(
            (new SettingsTab('contactInfo', __('Company Information', 'bookiflex')))
                ->addFieldsFactory($this->fieldsConfig->companySettingsFactory())
        );

        $container->addTab(
            (new SettingsTab('rules', __('Rules & Agreements', 'bookiflex')))
                ->addFieldsFactory($this->fieldsConfig->rulesSettingsFactory())
        );

        $container->addTab(
            (new SettingsTab('payment', __('Payment', 'bookiflex')))
                ->addFieldsFactory($this->fieldsConfig->bankAccountFactory())
        );

        $container->addTab(
            (new SettingsTab('appearance', __('Appearance', 'bookiflex')))
                ->addFieldsFactory($this->fieldsConfig->magicButtonFactory())
                ->addFieldsFactory($this->fieldsConfig->widgetAppearanceFactory())
        );

        $this->addContainer($container);
    }

    /**
     * Add a new settings container (menu item)
     */
    public function addContainer(SettingsContainer $container): self
    {
        $this->containers[$container->getId()] = $container;
        return $this;
    }

    /**
     * Get a specific container by ID
     */
    public function getContainer(string $containerId): ?SettingsContainer
    {
        return $this->containers[$containerId] ?? null;
    }

    /**
     * Add settings to an existing container
     *
     * @param array $config Configuration array.
     * ```
     * [[
     *   'container' => 'container_id', // optional, defaults to 'bflex__settings'
     *   'tab' => 'tab_name',
     *   'name' => 'Tab Name',
     *   'factory' => 'callable_factory',
     * ]],
     * ```
     */
    public function addSettings(array $config = []): void
    {
        foreach ($config as $value) {
            if (!is_array($value) || !isset($value['tab'], $value['name'], $value['factory']) || !is_callable($value['factory'])) {
                continue;
            }

            $containerId = $value['container'] ?? 'bflex__settings';
            $container = $this->getContainer($containerId);

            if (!$container) {
                continue;
            }

            $tabId = $value['tab'];
            $tabs = $container->getTabs();

            if (isset($tabs[$tabId])) {
                // Add factory to existing tab
                $tabs[$tabId]->addFieldsFactory($value['factory']);
            } else {
                // Create new tab
                $container->addTab(
                    (new SettingsTab($tabId, $value['name']))
                        ->addFieldsFactory($value['factory'])
                );
            }
        }
    }

    /**
     * Create a new container with configuration
     *
     * @param array $config
     * ```
     * [
     *   'id' => 'container_id',
     *   'title' => 'Container Title',
     *   'parent' => 'parent_slug', // optional
     *   'layout' => 'tabbed-vertical', // optional
     *   'capability' => 'manage_options', // optional
     *   'tabs' => [
     *     [
     *       'id' => 'tab_id',
     *       'name' => 'Tab Name',
     *       'factory' => callable
     *     ]
     *   ]
     * ]
     * ```
     */
    public function createContainer(array $config): SettingsContainer
    {
        if (!isset($config['id'], $config['title'])) {
            throw new \InvalidArgumentException('Container must have id and title');
        }

        $container = new SettingsContainer($config['id'], $config['title']);

        if (isset($config['parent'])) {
            $container->setParent($config['parent']);
        }

        if (isset($config['layout'])) {
            $container->setLayout($config['layout']);
        }

        if (isset($config['capability'])) {
            $container->setCapability($config['capability']);
        }

        if (isset($config['tabs']) && is_array($config['tabs'])) {
            foreach ($config['tabs'] as $tabConfig) {
                if (!isset($tabConfig['id'], $tabConfig['name'], $tabConfig['factory'])) {
                    continue;
                }

                $tab = new SettingsTab($tabConfig['id'], $tabConfig['name']);
                $tab->addFieldsFactory($tabConfig['factory']);
                $container->addTab($tab);
            }
        }

        $this->addContainer($container);
        return $container;
    }

    public function register(): void
    {
        $this->plugin->addAction('carbon_fields_register_fields', [$this, 'registerFields']);
        $this->plugin->addFilter('carbon_fields_theme_options_container_admin_only_access', [$this, 'checkAccess'], 10, 2);
    }

    /**
     * Check access for containers based on capabilities
     */
    public function checkAccess(bool $enable, $container): bool
    {
        foreach ($this->containers as $settingsContainer) {
            if ($settingsContainer->getCapability() && current_user_can($settingsContainer->getCapability())) {
                return false;
            }
        }
        return $enable;
    }

    public function registerFields(): void
    {
        foreach ($this->containers as $container) {
            $container->build();
        }
    }
}
