<?php

namespace FleekDash\Integrations\Core;

defined('ABSPATH') || exit;

/**
 * Unified Settings Manager for Integrations
 *
 * Provides a clean API for managing integration settings
 */
class SettingsManager
{
    private Container $container;
    private Cache $cache;
    private array $schemas = [];
    private array $sections = [];

    public function __construct(Container $container, Cache $cache)
    {
        $this->container = $container;
        $this->cache = $cache;
        $this->registerHooks();
    }

    /**
     * Register WordPress hooks
     */
    private function registerHooks(): void
    {
        add_action('rest_api_init', [$this, 'registerRestRoutes']);
        add_action('admin_init', [$this, 'registerSettingsSections']);
    }

    /**
     * Register a settings schema for an integration
     */
    public function registerSchema(string $integrationId, array $schema): void
    {
        $this->schemas[$integrationId] = $schema;

        // Register with WordPress settings API
        $this->registerWordPressSettings($integrationId, $schema);
    }

    /**
     * Register a settings section
     */
    public function registerSection(string $id, array $config): void
    {
        $defaults = [
            'title' => '',
            'description' => '',
            'icon' => 'cog',
            'permissions' => 'manage_options',
            'position' => 999
        ];

        $this->sections[$id] = array_merge($defaults, $config);
    }

    /**
     * Get settings for an integration
     */
    public function getSettings(string $integrationId): array
    {
        $optionName = $this->getOptionName($integrationId);
        $defaults = $this->getDefaults($integrationId);

        $settings = get_option($optionName, []);

        return array_merge($defaults, $settings);
    }

    /**
     * Update settings for an integration
     */
    public function updateSettings(string $integrationId, array $settings): bool
    {
        // Validate against schema
        $validation = $this->validateSettings($integrationId, $settings);
        if (is_wp_error($validation)) {
            return false;
        }

        $optionName = $this->getOptionName($integrationId);
        $result = update_option($optionName, $settings);

        if ($result) {
            // Clear related caches
            $this->cache->delete("settings_{$integrationId}");

            // Fire settings updated hook
            do_action("fleekdash_settings_updated_{$integrationId}", $settings);
            do_action('fleekdash_settings_updated', $integrationId, $settings);
        }

        return $result;
    }

    /**
     * Get a specific setting value
     */
    public function getSetting(string $integrationId, string $key, $default = null)
    {
        $settings = $this->getSettings($integrationId);
        return $settings[$key] ?? $default;
    }

    /**
     * Update a specific setting
     */
    public function updateSetting(string $integrationId, string $key, $value): bool
    {
        $settings = $this->getSettings($integrationId);
        $settings[$key] = $value;

        return $this->updateSettings($integrationId, $settings);
    }

    /**
     * Validate settings against schema
     */
    public function validateSettings(string $integrationId, array $settings): bool|\WP_Error
    {
        if (!isset($this->schemas[$integrationId])) {
            return new \WP_Error('no_schema', 'No schema found for integration');
        }

        $schema = $this->schemas[$integrationId];
        $errors = [];

        foreach ($schema as $field => $config) {
            $value = $settings[$field] ?? null;

            // Check required fields
            if ($config['required'] ?? false) {
                if ($value === null || $value === '') {
                    $errors[] = "Field '{$field}' is required";
                    continue;
                }
            }

            // Skip validation if field is empty and not required
            if ($value === null || $value === '') {
                continue;
            }

            // Type validation
            $validation = $this->validateField($field, $value, $config);
            if (is_wp_error($validation)) {
                $errors[] = $validation->get_error_message();
            }
        }

        if (!empty($errors)) {
            return new \WP_Error('validation_failed', implode(', ', $errors));
        }

        return true;
    }

    /**
     * Validate individual field
     */
    private function validateField(string $field, $value, array $config): bool|\WP_Error
    {
        $type = $config['type'] ?? 'string';

        switch ($type) {
            case 'string':
                if (!is_string($value)) {
                    return new \WP_Error('invalid_type', "Field '{$field}' must be a string");
                }

                if (isset($config['min_length']) && strlen($value) < $config['min_length']) {
                    return new \WP_Error('too_short', "Field '{$field}' is too short");
                }

                if (isset($config['max_length']) && strlen($value) > $config['max_length']) {
                    return new \WP_Error('too_long', "Field '{$field}' is too long");
                }
                break;

            case 'number':
            case 'integer':
                if (!is_numeric($value)) {
                    return new \WP_Error('invalid_type', "Field '{$field}' must be a number");
                }

                if (isset($config['min']) && $value < $config['min']) {
                    return new \WP_Error('too_small', "Field '{$field}' is too small");
                }

                if (isset($config['max']) && $value > $config['max']) {
                    return new \WP_Error('too_large', "Field '{$field}' is too large");
                }
                break;

            case 'boolean':
                if (!is_bool($value) && !in_array($value, [0, 1, '0', '1', 'true', 'false'])) {
                    return new \WP_Error('invalid_type', "Field '{$field}' must be a boolean");
                }
                break;

            case 'email':
                if (!is_email($value)) {
                    return new \WP_Error('invalid_email', "Field '{$field}' must be a valid email");
                }
                break;

            case 'url':
                if (!filter_var($value, FILTER_VALIDATE_URL)) {
                    return new \WP_Error('invalid_url', "Field '{$field}' must be a valid URL");
                }
                break;

            case 'select':
                $options = array_keys($config['options'] ?? []);
                if (!in_array($value, $options)) {
                    return new \WP_Error('invalid_option', "Field '{$field}' has invalid option");
                }
                break;
        }

        return true;
    }

    /**
     * Get default values from schema
     */
    private function getDefaults(string $integrationId): array
    {
        if (!isset($this->schemas[$integrationId])) {
            return [];
        }

        $defaults = [];
        foreach ($this->schemas[$integrationId] as $field => $config) {
            if (isset($config['default'])) {
                $defaults[$field] = $config['default'];
            }
        }

        return $defaults;
    }

    /**
     * Get WordPress option name for integration
     */
    private function getOptionName(string $integrationId): string
    {
        return "fleekdash_{$integrationId}_settings";
    }

    /**
     * Register with WordPress Settings API
     */
    private function registerWordPressSettings(string $integrationId, array $schema): void
    {
        $optionName = $this->getOptionName($integrationId);

        \register_setting('fleekdash_settings', $optionName, [
            'type' => 'object',
            'description' => "Settings for {$integrationId} integration",
            'sanitize_callback' => function ($value) use ($integrationId) {
                $validation = $this->validateSettings($integrationId, $value);
                return is_wp_error($validation) ? [] : $value;
            }
        ]);
    }

    /**
     * Register settings sections for admin
     */
    public function registerSettingsSections(): void
    {
        foreach ($this->sections as $id => $section) {
            \add_settings_section(
                $id,
                $section['title'],
                function () use ($section) {
                    if (!empty($section['description'])) {
                        echo '<p>' . esc_html($section['description']) . '</p>';
                    }
                },
                'fleekdash_settings',
            );
        }
    }

    /**
     * Register REST API routes
     */
    public function registerRestRoutes(): void
    {
        // Get all settings
        register_rest_route('fleekdash/v1', '/settings', [
            'methods' => 'GET',
            'callback' => [$this, 'restGetAllSettings'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            }
        ]);

        // Get integration settings
        register_rest_route('fleekdash/v1', '/settings/(?P<integration>[a-zA-Z0-9-_]+)', [
            'methods' => 'GET',
            'callback' => [$this, 'restGetSettings'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            }
        ]);

        // Update integration settings
        register_rest_route('fleekdash/v1', '/settings/(?P<integration>[a-zA-Z0-9-_]+)', [
            'methods' => 'POST',
            'callback' => [$this, 'restUpdateSettings'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            }
        ]);

        // Get settings schema
        register_rest_route('fleekdash/v1', '/settings/(?P<integration>[a-zA-Z0-9-_]+)/schema', [
            'methods' => 'GET',
            'callback' => [$this, 'restGetSchema'],
            'permission_callback' => function () {
                return current_user_can('manage_options');
            }
        ]);
    }

    /**
     * REST: Get all settings
     */
    public function restGetAllSettings(): \WP_REST_Response
    {
        $allSettings = [];

        foreach (array_keys($this->schemas) as $integrationId) {
            $allSettings[$integrationId] = $this->getSettings($integrationId);
        }

        return rest_ensure_response([
            'success' => true,
            'data' => $allSettings
        ]);
    }

    /**
     * REST: Get integration settings
     */
    public function restGetSettings(\WP_REST_Request $request): \WP_REST_Response
    {
        $integration = $request->get_param('integration');
        $settings = $this->getSettings($integration);

        return rest_ensure_response([
            'success' => true,
            'data' => $settings
        ]);
    }

    /**
     * REST: Update integration settings
     */
    public function restUpdateSettings(\WP_REST_Request $request): \WP_REST_Response|\WP_Error
    {
        $integration = $request->get_param('integration');
        $settings = $request->get_json_params();

        $validation = $this->validateSettings($integration, $settings);
        if (is_wp_error($validation)) {
            return $validation;
        }

        $success = $this->updateSettings($integration, $settings);

        if ($success) {
            return rest_ensure_response([
                'success' => true,
                'message' => 'Settings updated successfully'
            ]);
        } else {
            return new \WP_Error('update_failed', 'Failed to update settings', ['status' => 500]);
        }
    }

    /**
     * REST: Get settings schema
     */
    public function restGetSchema(\WP_REST_Request $request): \WP_REST_Response|\WP_Error
    {
        $integration = $request->get_param('integration');

        if (!isset($this->schemas[$integration])) {
            return new \WP_Error('schema_not_found', 'Schema not found', ['status' => 404]);
        }

        return rest_ensure_response([
            'success' => true,
            'data' => $this->schemas[$integration]
        ]);
    }

    /**
     * Export settings for backup
     */
    public function exportSettings(): array
    {
        $export = [];

        foreach (array_keys($this->schemas) as $integrationId) {
            $export[$integrationId] = $this->getSettings($integrationId);
        }

        return $export;
    }

    /**
     * Import settings from backup
     */
    public function importSettings(array $settings): bool
    {
        $success = true;

        foreach ($settings as $integrationId => $integrationSettings) {
            if (isset($this->schemas[$integrationId])) {
                $result = $this->updateSettings($integrationId, $integrationSettings);
                if (!$result) {
                    $success = false;
                }
            }
        }

        return $success;
    }
}
