<?php

namespace FleekDash\API;

use FleekDash\Controllers\License\LicenseHelpers;
use FleekDash\Services\FeatureSupabaseService;
use FleekDash\Services\FeatureUsageMetricsService;
use FleekDash\Services\LabsFeaturesService;
use FleekDash\Core\PermissionFeatureResolver;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

// Prevent direct access to this file
defined("ABSPATH") || exit();

// Load debug helpers
if (!function_exists('fleekdash_log_debug')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

class FeatureController
{
    private const ACCEPT_JSON = 'application/json';
    private const API_NAMESPACE = 'fleekdash/v1';
    private const MESSAGE_NO_ACTIVE_LICENSE = 'No active license found';
    private const MESSAGE_FEATURE_KEY_REQUIRED = 'Feature key is required';
    private const MESSAGE_UNKNOWN_ERROR = 'Unknown error';

    private static ?self $instance = null;

    private string $supabaseUrl = '';

    private string $supabaseKey = '';

    private string $apiVersion = 'v1';

    private FeatureRequestSanitizer $requestSanitizer;

    private FeatureUsageMetricsService $usageMetrics;

    /**
     * Define the TTL for feature cache in seconds
     * 5 minutes = 300 seconds
     */
    private int $featureCacheTtl = 300; // 5 minutes

    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct()
    {
        $this->supabaseUrl = defined('FLEEKDASH_SUPABASE_URL') ? \FLEEKDASH_SUPABASE_URL : '';
        $this->supabaseKey = defined('FLEEKDASH_SUPABASE_KEY') ? \FLEEKDASH_SUPABASE_KEY : '';
        $this->apiVersion = 'v1';
        $this->requestSanitizer = new FeatureRequestSanitizer();
        $this->usageMetrics = new FeatureUsageMetricsService();

        // MIGRATED TO V2.2: FeaturesRoutes (Phase 4.2)
        // add_action removed - routes now registered via FeaturesRoutes
        // \add_action('rest_api_init', [$this, 'register_routes']);
    }

    public function registerRoutes()
    {
        \register_rest_route(self::API_NAMESPACE, '/features/user', [
            'methods' => 'GET',
            'callback' => [$this, 'getUserFeatures'],
            'permission_callback' => function () {
                // V2.2 FIX: Any logged-in user can check their features
                return \is_user_logged_in();
            },
        ]);

        \register_rest_route(self::API_NAMESPACE, '/features/check', [
            'methods' => 'POST',
            'callback' => [$this, 'checkFeature'],
            'permission_callback' => function () {
                // V2.2 FIX: Any logged-in user can check features
                return \is_user_logged_in();
            },
        ]);

        \register_rest_route(self::API_NAMESPACE, '/features/check-limit', [
            'methods' => 'POST',
            'callback' => [$this, 'checkFeatureLimit'],
            'permission_callback' => function () {
                // V2.2 FIX: Any logged-in user can check limits
                return \is_user_logged_in();
            },
        ]);

        \register_rest_route(self::API_NAMESPACE, '/features/usage', [
            'methods' => 'GET',
            'callback' => [$this, 'getFeatureUsage'],
            'permission_callback' => function () {
                // V2.2 FIX: Any logged-in user can check usage
                return \is_user_logged_in();
            },
        ]);
    }

    /**
     * Get all features and limits for the current user's license
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response|WP_Error
     */
    public function getUserFeatures(WP_REST_Request $request)
    {
        $app_name = $this->requestSanitizer->sanitizeAppName($request->get_param('app_name'));
        $force_refresh = filter_var($request->get_param('force_refresh'), FILTER_VALIDATE_BOOLEAN);
        $license_status = \get_option('fleekdash_v2_license_status', 'inactive');
        if ($license_status !== 'active') {
            $response = new WP_REST_Response([
                'success' => false,
                'message' => self::MESSAGE_NO_ACTIVE_LICENSE,
                'error_code' => 'license_inactive',
                'blocking_reason' => 'license',
                'features' => [],
                'limits' => []
            ], 200);
            $this->applyNoStoreHeaders($response);
            return $response;
        }

        $license_data = LicenseHelpers::getCanonicalLicenseRecord(\get_option('fleekdash_v2_license_data'));
        if (!$license_data || !isset($license_data['deal_tier_id'])) {
            $response = new WP_REST_Response([
                'success' => false,
                'message' => 'No tier information found',
                'error_code' => 'tier_missing',
                'blocking_reason' => 'tier',
                'features' => [],
                'limits' => []
            ], 200);
            $this->applyNoStoreHeaders($response);
            return $response;
        }

        $response = $this->buildUserFeaturesResponse((string) $license_data['deal_tier_id'], (string) $app_name, $force_refresh);
        if ($response instanceof WP_REST_Response) {
            $this->applyNoStoreHeaders($response);
        }
        return $response;
    }

    /**
     * Check if a specific feature is enabled for the user
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response|WP_Error
     */
    public function checkFeature(WP_REST_Request $request)
    {
        $feature_key = $request->get_param('feature_key');
        $feature_key = PermissionFeatureResolver::normalizeFeatureKey((string) $feature_key);
        $app_name = $this->requestSanitizer->sanitizeAppName($request->get_param('app_name'));
        $feature_key = $this->requestSanitizer->sanitizeFilterToken($feature_key);

        $response = null;
        if ($feature_key === '') {
            $response = new WP_Error(
                'missing_feature_key',
                self::MESSAGE_FEATURE_KEY_REQUIRED,
                ['status' => 400]
            );
        } elseif (\get_option('fleekdash_v2_license_status', 'inactive') !== 'active') {
            $response = new WP_REST_Response([
                'success' => false,
                'has_feature' => false,
                'message' => self::MESSAGE_NO_ACTIVE_LICENSE,
            ], 200);
            $this->applyNoStoreHeaders($response);
        } else {
            $license_data = LicenseHelpers::getCanonicalLicenseRecord(\get_option('fleekdash_v2_license_data'));
            if (!\is_array($license_data) || !isset($license_data['deal_tier_id'])) {
                $response = new WP_REST_Response([
                    'success' => false,
                    'has_feature' => false,
                    'message' => 'No tier information found',
                    'error_code' => 'tier_missing',
                ], 200);
                $this->applyNoStoreHeaders($response);
            } else {
                $response = $this->resolveFeatureCheckResponse((string) $feature_key, (string) $app_name);
            }
        }

        return $response;
    }

    /**
     * Check feature limit and current usage
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response|WP_Error
     */
    public function checkFeatureLimit(WP_REST_Request $request)
    {
        $feature_key = $request->get_param('feature_key');
        $feature_key = PermissionFeatureResolver::normalizeFeatureKey((string) $feature_key);
        $feature_key = $this->requestSanitizer->sanitizeFilterToken($feature_key);
        $limit_key = $this->requestSanitizer->sanitizeFilterToken((string) ($request->get_param('limit_key') ?: 'default'));
        $app_name = $this->requestSanitizer->sanitizeAppName($request->get_param('app_name'));

        if (empty($feature_key)) {
            return new WP_Error(
                'missing_feature_key',
                self::MESSAGE_FEATURE_KEY_REQUIRED,
                ['status' => 400]
            );
        }

        $license_data = LicenseHelpers::getCanonicalLicenseRecord(\get_option('fleekdash_v2_license_data'));
        if (!$license_data || !isset($license_data['deal_tier_id'])) {
            return new WP_REST_Response([
                'success' => false,
                'has_limit' => false,
                'message' => self::MESSAGE_NO_ACTIVE_LICENSE
            ], 200);
        }

        return $this->resolveFeatureLimitResponse(
            (string) $license_data['deal_tier_id'],
            (string) $feature_key,
            (string) $limit_key,
            (string) $app_name
        );
    }

    private function applyNoStoreHeaders(WP_REST_Response $response): void
    {
        $response->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
        $response->header('Pragma', 'no-cache');
        $response->header('Expires', '0');
    }

    private function buildUserFeaturesResponse(string $tier_id, string $app_name, bool $force_refresh)
    {
        $labsService = LabsFeaturesService::init();
        $cache_key = "fleekdash_v2_features_{$app_name}_{$tier_id}";

        if (!$force_refresh) {
            $cached_data = \get_transient($cache_key);
            if ($cached_data !== false && \is_array($cached_data)) {
                return $this->buildUserFeaturesCachedRestResponse(
                    $labsService,
                    $cached_data,
                    $tier_id,
                    $app_name,
                    'Features loaded from cache',
                    false,
                    null
                );
            }
        }

        $fetcher = new FeatureSupabaseService($this->supabaseUrl, $this->supabaseKey);
        $features_data = $fetcher->fetchUserFeatures($tier_id, $app_name);
        if (is_wp_error($features_data)) {
            return $this->buildUserFeaturesResponseAfterFetchError(
                $features_data,
                $labsService,
                $cache_key,
                $tier_id,
                $app_name
            );
        }

        $enhanced = $labsService->enhanceFeaturesData([
            'features' => $features_data['features'] ?? [],
            'limits' => $features_data['limits'] ?? [],
            'tier_id' => $tier_id,
            'app_name' => $app_name,
        ]);

        \set_transient($cache_key, $features_data, $this->featureCacheTtl);

        return new WP_REST_Response([
            'success' => true,
            'message' => 'Features loaded successfully',
            'cached' => false,
            'cache_ttl' => $this->featureCacheTtl,
            'tier_id' => $tier_id,
            'app_name' => $app_name,
            'features' => $enhanced['features'] ?? [],
            'limits' => $enhanced['limits'] ?? [],
            'labs_overrides' => $enhanced['labs_overrides'] ?? [],
        ], 200);
    }

    /**
     * @param array<string, mixed> $cached_data
     */
    private function buildUserFeaturesCachedRestResponse(
        LabsFeaturesService $labsService,
        array $cached_data,
        string $tier_id,
        string $app_name,
        string $message,
        bool $degraded,
        ?string $degraded_reason
    ): WP_REST_Response {
        $enhanced = $labsService->enhanceFeaturesData([
            'features' => $cached_data['features'] ?? [],
            'limits' => $cached_data['limits'] ?? [],
            'tier_id' => $tier_id,
            'app_name' => $app_name,
        ]);

        $payload = [
            'success' => true,
            'message' => $message,
            'cached' => true,
            'cache_ttl' => $this->featureCacheTtl,
            'tier_id' => $tier_id,
            'app_name' => $app_name,
            'features' => $enhanced['features'] ?? [],
            'limits' => $enhanced['limits'] ?? [],
            'labs_overrides' => $enhanced['labs_overrides'] ?? [],
        ];
        if ($degraded) {
            $payload['degraded'] = true;
            if ($degraded_reason !== null && $degraded_reason !== '') {
                $payload['degraded_reason'] = $degraded_reason;
            }
        }

        return new WP_REST_Response($payload, 200);
    }

    private function buildUserFeaturesResponseAfterFetchError(
        WP_Error $features_data,
        LabsFeaturesService $labsService,
        string $cache_key,
        string $tier_id,
        string $app_name
    ): WP_REST_Response {
        $error_message = $features_data->get_error_message();
        \fleekdash_log_error('FeatureController: fetchUserFeatures failed: ' . $error_message);

        $cached_stale = \get_transient($cache_key);
        $has_stale = \is_array($cached_stale)
            && (\array_key_exists('features', $cached_stale) || \array_key_exists('limits', $cached_stale));
        if ($has_stale) {
            return $this->buildUserFeaturesCachedRestResponse(
                $labsService,
                $cached_stale,
                $tier_id,
                $app_name,
                'Features loaded from cache (Supabase fetch failed; serving last known data)',
                true,
                $features_data->get_error_code()
            );
        }

        return new WP_REST_Response([
            'success' => false,
            'message' => 'Failed to fetch features: ' . $error_message,
            'error_code' => $features_data->get_error_code(),
            'features' => [],
            'limits' => [],
        ], 200);
    }

    /**
     * Single source of truth with PermissionFeatureResolver: tier cache + Labs, same as /features/user.
     */
    private function resolveFeatureCheckResponse(string $feature_key, string $app_name): WP_REST_Response
    {
        $has_feature = \class_exists(PermissionFeatureResolver::class)
            ? PermissionFeatureResolver::hasFeature($feature_key, $app_name)
            : false;

        $response = new WP_REST_Response([
            'success' => true,
            'has_feature' => $has_feature,
            'feature_key' => $feature_key,
            'app_name' => $app_name,
        ], 200);
        $this->applyNoStoreHeaders($response);

        return $response;
    }

    private function resolveFeatureLimitResponse(string $tier_id, string $feature_key, string $limit_key, string $app_name)
    {
        $cache_key = "fleekdash_v2_limit_check_{$app_name}_{$tier_id}_{$feature_key}_{$limit_key}";
        $cached_result = \get_transient($cache_key);
        if ($cached_result !== false) {
            return new WP_REST_Response([
                'success' => true,
                'limit' => $cached_result,
                'cached' => true,
                'feature_key' => $feature_key,
                'limit_key' => $limit_key,
                'app_name' => $app_name
            ], 200);
        }

        $limit_data = $this->getFeatureLimitFromDb($tier_id, $feature_key, $limit_key, $app_name);
        if (is_wp_error($limit_data)) {
            return new WP_Error(
                'limit_check_failed',
                'Failed to check limit: ' . ($limit_data ? $limit_data->get_error_message() : self::MESSAGE_UNKNOWN_ERROR),
                ['status' => 500]
            );
        }

        $current_usage = $this->usageMetrics->getCurrentUsage($feature_key, $limit_key, $app_name);
        $result = [
            'has_limit' => $limit_data !== null,
            'limit_value' => $limit_data['limit_value'] ?? 0,
            'is_unlimited' => $limit_data['is_unlimited'] ?? false,
            'limit_type' => $limit_data['limit_type'] ?? 'count',
            'limit_unit' => $limit_data['limit_unit'] ?? 'units',
            'current_usage' => $current_usage,
            'remaining' => $limit_data ? $this->usageMetrics->calculateRemaining($limit_data, $current_usage) : null,
            'display_value' => $limit_data ? $this->usageMetrics->formatDisplayValue($limit_data) : 'No limit'
        ];

        \set_transient($cache_key, $result, $this->featureCacheTtl);
        return new WP_REST_Response([
            'success' => true,
            'limit' => $result,
            'cached' => false,
            'feature_key' => $feature_key,
            'limit_key' => $limit_key,
            'app_name' => $app_name
        ], 200);
    }

    /**
     * Get current usage for a feature
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response|WP_Error
     */
    public function getFeatureUsage(WP_REST_Request $request)
    {
        $feature_key = $request->get_param('feature_key');
        $feature_key = PermissionFeatureResolver::normalizeFeatureKey((string) $feature_key);
        $feature_key = $this->requestSanitizer->sanitizeFilterToken($feature_key);
        $limit_key = $this->requestSanitizer->sanitizeFilterToken((string) ($request->get_param('limit_key') ?: 'default'));
        $app_name = $this->requestSanitizer->sanitizeAppName($request->get_param('app_name'));

        if (empty($feature_key)) {
            return new WP_Error(
                'missing_feature_key',
                self::MESSAGE_FEATURE_KEY_REQUIRED,
                ['status' => 400]
            );
        }

        $current_usage = $this->usageMetrics->getCurrentUsage($feature_key, $limit_key, $app_name);

        return new WP_REST_Response([
            'success' => true,
            'feature_key' => $feature_key,
            'limit_key' => $limit_key,
            'app_name' => $app_name,
            'current_usage' => $current_usage
        ], 200);
    }

    /**
     * Get feature limit from database
     *
     * @param string $tier_id
     * @param string $feature_key
     * @param string $limit_key
     * @param string $app_name
     * @return array|null|WP_Error
     */
    private function getFeatureLimitFromDb($tier_id, $feature_key, $limit_key, $app_name)
    {
        $result = null;
        if (empty($this->supabaseUrl) || empty($this->supabaseKey)) {
            $result = new WP_Error(
                'supabase_config_missing',
                'Supabase configuration is missing',
                ['status' => 500]
            );
        } else {
            try {
                $url = $this->supabaseUrl . '/rest/' . $this->apiVersion . '/license_tier_feature_limits';
                $safe_tier_id = $this->requestSanitizer->encodePostgrestValue((string) $tier_id);
                $safe_limit_key = $this->requestSanitizer->encodePostgrestValue((string) $limit_key);
                $safe_feature_key = $this->requestSanitizer->encodePostgrestValue((string) $feature_key);
                $safe_app_name = $this->requestSanitizer->encodePostgrestValue((string) $app_name);
                $query = "?tier_id=eq.{$safe_tier_id}&limit_key=eq.{$safe_limit_key}&select=*&tool_available_features.feature_key=eq.{$safe_feature_key}&tool_available_features.app_name=eq.{$safe_app_name}";

                $response = \wp_remote_get($url . $query, [
                    'headers' => [
                        'apikey' => $this->supabaseKey,
                        'Authorization' => 'Bearer ' . $this->supabaseKey,
                        'Accept' => self::ACCEPT_JSON,
                    ],
                    'timeout' => 10,
                    'sslverify' => false,
                ]);

                if (\is_wp_error($response)) {
                    $result = new WP_Error(
                        'limit_fetch_failed',
                        'Failed to fetch limit: ' . ($response ? $response->get_error_message() : self::MESSAGE_UNKNOWN_ERROR),
                        ['status' => 500]
                    );
                } else {
                    $body = json_decode(wp_remote_retrieve_body($response), true);
                    $result = !empty($body) && isset($body[0]) ? $body[0] : null;
                }
            } catch (\Exception $e) {
                $result = new WP_Error(
                    'limit_fetch_exception',
                    'Exception fetching limit: ' . $e->getMessage(),
                    ['status' => 500]
                );
            }
        }

        return $result;
    }

    /**
     * Clear all features cache for all apps and tiers
     * Called automatically when license status changes
     *
     * @return int Number of cache entries cleared
     */
    public function clearFeaturesCache()
    {
        global $wpdb;

        // Count cache entries before clearing
        $count_before = $wpdb->get_var(
            "SELECT COUNT(*) FROM {$wpdb->options}
             WHERE option_name LIKE '_transient_fleekdash_v2_features_%'
             OR option_name LIKE '_transient_timeout_fleekdash_v2_features_%'"
        );

        // Get all feature-related transients
        $transients = $wpdb->get_results(
            "SELECT option_name FROM {$wpdb->options}
             WHERE option_name LIKE '_transient_fleekdash_v2_features_%'
             OR option_name LIKE '_transient_timeout_fleekdash_v2_features_%'"
        );

        $cleared_count = 0;
        foreach ($transients as $transient) {
            $option_name = $transient->option_name;

            // Extract transient name
            if (strpos($option_name, '_transient_') === 0) {
                $transient_name = substr($option_name, 11); // Remove '_transient_'
            } elseif (strpos($option_name, '_transient_timeout_') === 0) {
                $transient_name = substr($option_name, 19); // Remove '_transient_timeout_'
            } else {
                continue;
            }

            // Delete the transient
            \delete_transient($transient_name);
            $cleared_count++;
        }

        // Log cache clearing for debugging
        fleekdash_log_info("FleekDash: Cleared {$cleared_count} feature cache entries (was {$count_before})");

        return $cleared_count;
    }

    /**
     * Clear features cache for specific app and tier
     *
     * @param string $app_name
     * @param string $tier_id
     * @return bool Success status
     */
    public function clearFeaturesCacheForApp($app_name, $tier_id)
    {
        $cache_key = "fleekdash_v2_features_{$app_name}_{$tier_id}";
        $result = \delete_transient($cache_key);

        fleekdash_log_info("FleekDash: Cleared cache for {$app_name} tier {$tier_id}: " . ($result ? 'success' : 'not found'));

        return $result;
    }
}

final class FeatureRequestSanitizer
{
    private const DEFAULT_APP_NAME = 'fleekdash';
    private const VALID_APP_NAMES = ['fleekdash', 'app2', 'app3'];

    public function sanitizeAppName(mixed $app_name): string
    {
        $value = strtolower(trim((string) $app_name));
        if ($value === '') {
            return self::DEFAULT_APP_NAME;
        }

        if (!in_array($value, self::VALID_APP_NAMES, true)) {
            return self::DEFAULT_APP_NAME;
        }

        return $value;
    }

    public function sanitizeFilterToken(string $value): string
    {
        $trimmed = trim($value);
        if ($trimmed === '') {
            return '';
        }

        if (!preg_match('/^[a-zA-Z0-9._-]+$/', $trimmed)) {
            return '';
        }

        return $trimmed;
    }

    public function encodePostgrestValue(string $value): string
    {
        return rawurlencode($value);
    }
}
