<?php
/**
 * Labs Features Service
 *
 * Applies Labs (beta/experimental) overrides across FleekDash.
 * - Normalizes stored overrides
 * - Enhances feature payloads returned by the API
 * - Provides helpers for Labs settings controllers
 *
 * @package FleekDash\Services
 */

namespace FleekDash\Services;

use WP_REST_Request;
use WP_REST_Response;

defined('ABSPATH') || exit;

class LabsFeaturesService
{
    private const OPTION_KEY = '_fleekdash_labs_overrides';
    private const LAB_TYPES = ['beta', 'experimental'];

    /**
     * Features that graduated from Labs: tier/plan only, no Labs toggle or default-off behaviour.
     * Keys must match tool_available_features.feature_key (sanitize_key).
     *
     * @var list<string>
     */
    private const GRADUATED_FROM_LABS_KEYS = [
        'menu_management',
        'theme_live_editor',
        'theme_management',
    ];

    private static ?self $instance = null;
    private bool $hooksRegistered = false;

    /**
     * Singleton bootstrap.
     */
    public static function init(): self
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        if (!self::$instance->hooksRegistered) {
            self::$instance->registerHooks();
        }

        return self::$instance;
    }

    private function registerHooks(): void
    {
        \add_filter('rest_post_dispatch', [$this, 'handleRestResponse'], 20, 3);
        $this->hooksRegistered = true;
    }

    /**
     * Apply overrides to API responses.
     */
    public function handleRestResponse($response, $server, $request)
    {
        if (!$response instanceof WP_REST_Response
            || !$request instanceof WP_REST_Request
            || !($server instanceof \WP_REST_Server)) {
            return $response;
        }

        $route = trim((string) $request->get_route(), '/');
        if ($route !== 'fleekdash/v1/features/user') {
            return $response;
        }

        $data = $response->get_data();
        if (!is_array($data) || empty($data)) {
            return $response;
        }

        $enhanced = $this->enhanceFeaturesData($data);
        $response->set_data($enhanced);

        return $response;
    }

    /**
     * Enhance feature payload with Labs metadata and overrides.
     */
    public function enhanceFeaturesData(array $payload): array
    {
        $features = is_array($payload['features'] ?? null) ? $payload['features'] : [];
        $overrides = $this->getOverrides();

        if (!empty($features)) {
            $overrides = $this->pruneNonLabOverrides($features, $overrides);
            $features = $this->applyOverridesToFeatures($features, $overrides);
        }

        $payload['features'] = $features;
        $payload['labs_overrides'] = $overrides;

        return $payload;
    }

    /**
     * Return normalized overrides array.
     */
    public function getOverrides(): array
    {
        $raw = \get_option(self::OPTION_KEY, []);
        if (!is_array($raw)) {
            return [];
        }

        $normalized = [];
        foreach ($raw as $key => $value) {
            $normalized[\sanitize_key((string) $key)] = (bool) $value;
        }

        return $normalized;
    }

    /**
     * Save overrides to WordPress options.
     */
    public function saveOverrides(array $overrides): void
    {
        \update_option(self::OPTION_KEY, $this->sanitizeOverrides($overrides));
    }

    /**
     * Sanitize incoming overrides payload.
     */
    public function sanitizeOverrides(array $overrides): array
    {
        $sanitized = [];

        foreach ($overrides as $key => $value) {
            $sanitized[\sanitize_key((string) $key)] = (bool) $value;
        }

        return $sanitized;
    }

    /**
     * Filter labs features only.
     */
    public function filterLabsFeatures(array $features): array
    {
        return array_values(array_filter($features, function ($feature) {
            $key = \sanitize_key((string) ($feature['key'] ?? ''));
            if ($key === '' || $this->isGraduatedFromLabs($key)) {
                return false;
            }
            $type = strtolower((string) ($feature['type'] ?? ''));

            return in_array($type, self::LAB_TYPES, true);
        }));
    }

    /**
     * Produce normalized Labs feature payload for settings UI.
     */
    public function buildLabsFeaturePayload(array $features, ?array $overrides = null): array
    {
        $overrides = $overrides ?? $this->getOverrides();
        $features = $this->applyOverridesToFeatures($features, $overrides);
        $labsFeatures = $this->filterLabsFeatures($features);

        return array_map(function (array $feature) use ($overrides) {
            $key = \sanitize_key((string) ($feature['key'] ?? ''));
            $labsMeta = is_array($feature['labs'] ?? null) ? $feature['labs'] : [];

            $baseEnabled = (bool) ($labsMeta['base_enabled'] ?? $feature['is_enabled'] ?? false);
            $override = $key !== '' && array_key_exists($key, $overrides)
                ? (bool) $overrides[$key]
                : ($labsMeta['override'] ?? null);

            // For Labs features: if no explicit override exists, default to false (disabled)
            // baseEnabled only indicates plan access (available), not active state
            if ($labsMeta['resolved_enabled'] !== null) {
                $resolved = (bool) $labsMeta['resolved_enabled'];
            } elseif ($override !== null) {
                $resolved = (bool) $override;
            } else {
                // No override saved = feature should be disabled by default
                $resolved = false;
            }
            $planLabel = $labsMeta['plan_label'] ?? ($feature['label'] ?? null);

            return [
                'id' => $feature['id'] ?? null,
                'key' => $key,
                'name' => $feature['name'] ?? '',
                'description' => $feature['description'] ?? '',
                'category' => $feature['category'] ?? 'general',
                'type' => $feature['type'] ?? 'beta',
                'icon' => $feature['override_icon'] ?? $feature['icon'] ?? null,
                'label' => $feature['override_label'] ?? $feature['label'] ?? null,
                'url' => $feature['override_url'] ?? $feature['url'] ?? null,
                'media_associations' => $feature['media_associations'] ?? [],
                'available' => $baseEnabled,
                'enabled' => $resolved,
                'override' => $override,
                'plan_label' => $planLabel,
                'requires_plan' => !empty($planLabel),
            ];
        }, $labsFeatures);
    }

    /**
     * Apply Labs overrides to feature array.
     */
    public function applyOverridesToFeatures(array $features, array $overrides): array
    {
        if (empty($features)) {
            return $features;
        }

        foreach ($features as &$feature) {
            $type = strtolower((string) ($feature['type'] ?? ''));
            $key = \sanitize_key((string) ($feature['key'] ?? ''));
            $baseEnabled = (bool) ($feature['is_enabled'] ?? false);
            $planLabel = $feature['label'] ?? null;
            $isLabFeature = !$this->isGraduatedFromLabs($key)
                && in_array($type, self::LAB_TYPES, true);
            $override = null;

            if ($isLabFeature && array_key_exists($key, $overrides)) {
                $override = (bool) $overrides[$key];
                $resolved = $override;
            } elseif ($isLabFeature) {
                // Labs features without explicit override should start as disabled (false)
                // baseEnabled only indicates plan access, not active state
                $override = null;
                $resolved = false;
            } else {
                // Non-lab features use baseEnabled
                $override = null;
                $resolved = $baseEnabled;
            }

            $feature['labs'] = [
                'base_enabled' => $baseEnabled,
                'override' => $override,
                'resolved_enabled' => $resolved,
                'plan_label' => $planLabel,
                'is_lab_feature' => $isLabFeature,
            ];

            $feature['is_enabled'] = $resolved;
        }
        unset($feature);

        return $features;
    }

    /**
     * Build overrides payload from UI request.
     */
    public function extractOverridesFromPayload(array $payload, array $allowedKeys): array
    {
        $overrides = [];

        foreach ($payload as $item) {
            if (!is_array($item) || empty($item['key'])) {
                continue;
            }

            $key = \sanitize_key((string) $item['key']);
            if (!in_array($key, $allowedKeys, true)) {
                continue;
            }

            $overrides[$key] = (bool) ($item['enabled'] ?? false);
        }

        return $overrides;
    }

    /**
     * Automatically drop overrides for features that are no longer part of Labs.
     */
    private function pruneNonLabOverrides(array $features, array $overrides): array
    {
        if (empty($overrides)) {
            return $overrides;
        }

        $updated = $overrides;

        foreach (self::GRADUATED_FROM_LABS_KEYS as $graduatedKey) {
            if (array_key_exists($graduatedKey, $updated)) {
                unset($updated[$graduatedKey]);
            }
        }

        foreach ($features as $feature) {
            $key = \sanitize_key((string) ($feature['key'] ?? ''));
            $type = strtolower((string) ($feature['type'] ?? ''));

            if ($key === '' || in_array($type, self::LAB_TYPES, true)) {
                continue;
            }

            if (array_key_exists($key, $updated)) {
                unset($updated[$key]);
            }
        }

        if ($updated !== $overrides) {
            $this->saveOverrides($updated);
        }

        return $updated;
    }

    private function isGraduatedFromLabs(string $key): bool
    {
        $normalized = \sanitize_key($key);

        return $normalized !== '' && \in_array($normalized, self::GRADUATED_FROM_LABS_KEYS, true);
    }
}
