<?php

/**
 * Restriction helper functions
 *
 * Global helper functions for content restriction checks.
 *
 * @package ArraySubs\Functions
 */

defined('ABSPATH') || exit;

/**
 * Check if user has access to specific content
 *
 * @param int $user_id User ID.
 * @param int $post_id Post ID to check.
 * @return bool True if user can access.
 */
function arraysubs_user_can_access(int $user_id, int $post_id): bool
{
    $gating = new \ArraySubs\Features\MembersAccess\Services\ContentGating();
    return $gating->canUserAccessPost($user_id, $post_id);
}

/**
 * Check if current user can access specific content
 *
 * @param int $post_id Post ID to check.
 * @return bool True if user can access.
 */
function arraysubs_current_user_can_access(int $post_id): bool
{
    return arraysubs_user_can_access(get_current_user_id(), $post_id);
}

/**
 * Check if user meets specific conditions
 *
 * @param int   $user_id    User ID.
 * @param array $conditions Conditions array with 'logic' and 'rules' keys.
 * @return bool True if user meets all conditions.
 */
function arraysubs_user_meets_conditions(int $user_id, array $conditions): bool
{
    $evaluator = new \ArraySubs\Features\MembersAccess\Services\ConditionEvaluator();
    return $evaluator->evaluate($user_id, $conditions);
}

/**
 * Get user's lifetime purchase amount
 *
 * @param int $user_id User ID.
 * @return float Total amount spent.
 */
function arraysubs_get_user_lifetime_spent(int $user_id): float
{
    $history = new \ArraySubs\Features\MembersAccess\Services\PurchaseHistory();
    return $history->getLifetimeSpent($user_id);
}

/**
 * Check if user has purchased a specific product
 *
 * @param int  $user_id            User ID.
 * @param int  $product_id         Product ID.
 * @param bool $include_variations Check parent product when variation purchased.
 * @return bool True if user has purchased.
 */
function arraysubs_user_purchased_product(int $user_id, int $product_id, bool $include_variations = true): bool
{
    $history = new \ArraySubs\Features\MembersAccess\Services\PurchaseHistory();
    return $history->hasPurchasedProduct($user_id, $product_id, $include_variations);
}

/**
 * Check if user has active subscription
 *
 * @param int      $user_id    User ID.
 * @param int|null $product_id Optional product ID to check specific subscription.
 * @return bool True if user has active subscription.
 */
function arraysubs_user_has_active_subscription(int $user_id, ?int $product_id = null): bool
{
    $subscriptions = arraysubs_get_customer_subscriptions($user_id, ['arraysubs-active', 'arraysubs-trial']);

    if (empty($subscriptions)) {
        return false;
    }

    if ($product_id === null) {
        return true;
    }

    foreach ($subscriptions as $subscription) {
        $subscription_id = arraysubs_get_normalized_subscription_id($subscription);

        if ($subscription_id <= 0) {
            continue;
        }

        $sub_product_id = get_post_meta($subscription_id, '_product_id', true);
        if ((int) $sub_product_id === $product_id) {
            return true;
        }
    }

    return false;
}

/**
 * Get aggregated feature value from user's purchases
 *
 * @param int    $user_id     User ID.
 * @param string $feature_key Feature key to aggregate.
 * @param string $aggregation Aggregation mode: 'sum', 'max', 'any'.
 * @return mixed Aggregated feature value.
 */
function arraysubs_get_user_feature_value(int $user_id, string $feature_key, string $aggregation = 'sum')
{
    $evaluator = new \ArraySubs\Features\MembersAccess\Services\ConditionEvaluator();
    return $evaluator->getAggregatedFeatureValue($user_id, $feature_key, $aggregation);
}

/**
 * Get all content IDs accessible to user
 *
 * @param int    $user_id   User ID.
 * @param string $post_type Post type to check.
 * @return array Array of accessible post IDs.
 */
function arraysubs_get_accessible_content(int $user_id, string $post_type = 'post'): array
{
    $gating = new \ArraySubs\Features\MembersAccess\Services\ContentGating();
    return $gating->getAccessiblePostIds($user_id, $post_type);
}

/**
 * Check if a URL is restricted for a user
 *
 * @param string $url     URL to check.
 * @param int    $user_id User ID.
 * @return bool True if URL is restricted (user cannot access).
 */
function arraysubs_is_url_restricted(string $url, int $user_id): bool
{
    $restrictor = new \ArraySubs\Features\MembersAccess\Services\UrlRestrictor();
    return $restrictor->isUrlRestricted($url, $user_id);
}

/**
 * Check download limits for a user
 *
 * @param int $user_id    User ID.
 * @param int $product_id Product ID.
 * @return array Array with 'allowed', 'remaining', 'limit', 'used' keys.
 */
function arraysubs_check_download_limit(int $user_id, int $product_id): array
{
    $manager = new \ArraySubs\Features\MembersAccess\Services\DownloadManager();
    return $manager->checkDownloadLimit($user_id, $product_id);
}

/**
 * Check if Members Access feature is enabled
 *
 * @return bool True if enabled.
 */
function arraysubs_is_members_access_enabled(): bool
{
    return (bool) arraysubs_get_setting('members_access.enabled', true);
}

/**
 * Get restricted message for a post
 *
 * @param int $post_id Post ID.
 * @return string Restricted message HTML.
 */
function arraysubs_get_restricted_message(int $post_id): string
{
    $gating = new \ArraySubs\Features\MembersAccess\Services\ContentGating();
    return $gating->getRestrictedMessage($post_id);
}

/**
 * Synchronize WordPress roles for a user based on their subscriptions
 *
 * @param int $user_id User ID.
 * @return void
 */
function arraysubs_sync_user_roles(int $user_id): void
{
    $manager = new \ArraySubs\Features\MembersAccess\Services\RoleManager();
    $manager->syncUserRoles($user_id);
}

// ============================================================================
// FEATURE & USAGE HELPER FUNCTIONS
// ============================================================================

/**
 * Get features from a product or variation
 *
 * @param int $product_id Product or variation ID.
 * @return array Array of enabled features.
 */
function arraysubs_get_product_features(int $product_id): array
{
    $features_json = get_post_meta($product_id, '_arraysubs_features', true);

    if (empty($features_json)) {
        return [];
    }

    $features = json_decode($features_json, true);

    if (!is_array($features)) {
        return [];
    }

    // Filter to only enabled features
    return array_filter($features, function ($f) {
        return !empty($f['enabled']);
    });
}

/**
 * Get a specific feature from a product
 *
 * @param int    $product_id  Product or variation ID.
 * @param string $feature_key Feature name/key.
 * @return array|null Feature array or null if not found.
 */
function arraysubs_get_product_feature(int $product_id, string $feature_key): ?array
{
    $features = arraysubs_get_product_features($product_id);

    foreach ($features as $feature) {
        if (isset($feature['name']) && $feature['name'] === $feature_key) {
            return $feature;
        }
    }

    return null;
}

/**
 * Normalize a subscription reference into a subscription ID.
 *
 * Internal subscription collections can contain either `WP_Post` objects or
 * raw integer IDs depending on the caller. Helper functions should accept both.
 *
 * @param mixed $subscription Subscription object or ID.
 * @return int
 */
function arraysubs_get_normalized_subscription_id($subscription): int
{
    if ($subscription instanceof \WP_Post) {
        return (int) $subscription->ID;
    }

    if (is_numeric($subscription)) {
        return absint($subscription);
    }

    return 0;
}

/**
 * Get aggregated features for a customer across all their active subscriptions
 *
 * @param int    $customer_id      Customer ID.
 * @param string $aggregation_mode Aggregation mode: 'combine', 'max', 'per_subscription'.
 *                                 Legacy aliases 'sum', 'highest', and 'per_product' are supported.
 * @return array Features data. For 'per_subscription' mode returns array grouped by subscription,
 *               otherwise returns aggregated feature array.
 */
function arraysubs_get_customer_features(int $customer_id, string $aggregation_mode = 'sum'): array
{
    $aggregation_mode = arraysubs_normalize_customer_feature_aggregation_mode($aggregation_mode);
    $all_features = [];

    // Get active subscriptions
    $subscriptions = arraysubs_get_customer_subscriptions(
        $customer_id,
        ['arraysubs-active', 'arraysubs-trial']
    );

    if (empty($subscriptions)) {
        return [];
    }

    foreach ($subscriptions as $subscription) {
        $subscription_id = arraysubs_get_normalized_subscription_id($subscription);

        if ($subscription_id <= 0) {
            continue;
        }

        $product_id = get_post_meta($subscription_id, '_product_id', true);
        $variation_id = get_post_meta($subscription_id, '_variation_id', true);

        // Use variation features if available, otherwise product features
        $target_id = $variation_id ?: $product_id;

        if (!$target_id) {
            continue;
        }

        $features = arraysubs_get_product_features((int) $target_id);

        if (empty($features)) {
            continue;
        }

        if ($aggregation_mode === 'per_subscription') {
            $product = wc_get_product($target_id);
            $all_features[] = [
                'subscription_id' => $subscription_id,
                'product_id'      => (int) $target_id,
                'product_name'    => $product ? arraysubs_get_subscription_product_name($product) : __('Unknown Product', 'arraysubs'),
                'features'        => array_values($features),
            ];
        } else {
            // Aggregate features
            foreach ($features as $feature) {
                $key = $feature['name'] ?? '';
                if (empty($key)) {
                    continue;
                }

                if (!isset($all_features[$key])) {
                    $all_features[$key] = $feature;
                } else {
                    $all_features[$key] = arraysubs_aggregate_feature(
                        $all_features[$key],
                        $feature,
                        $aggregation_mode
                    );
                }
            }
        }
    }

    // For aggregation modes, convert back to indexed array
    if ($aggregation_mode !== 'per_subscription') {
        $all_features = array_values($all_features);
    }

    return $all_features;
}

/**
 * Aggregate two features based on aggregation mode
 *
 * @param array  $existing         Existing feature data.
 * @param array  $new              New feature to merge.
 * @param string $aggregation_mode Aggregation mode: 'combine', 'max'.
 * @return array Aggregated feature.
 */
function arraysubs_aggregate_feature(array $existing, array $new, string $aggregation_mode): array
{
    $result = $existing;
    $type = $existing['type'] ?? 'text';
    $aggregation_mode = arraysubs_normalize_customer_feature_aggregation_mode($aggregation_mode);

    switch ($type) {
        case 'toggle':
            // OR boolean values - if either is Yes/true, result is Yes
            $existing_bool = in_array(strtolower($existing['value'] ?? ''), ['yes', 'true', '1', 'on'], true);
            $new_bool = in_array(strtolower($new['value'] ?? ''), ['yes', 'true', '1', 'on'], true);
            $result['value'] = ($existing_bool || $new_bool) ? 'Yes' : 'No';
            break;

        case 'number':
            $existing_val = $existing['value'] ?? 0;
            $new_val = $new['value'] ?? 0;

            // Check for "unlimited"
            if (strtolower((string) $existing_val) === 'unlimited' || strtolower((string) $new_val) === 'unlimited') {
                $result['value'] = 'Unlimited';
            } elseif ($aggregation_mode === 'combine') {
                $result['value'] = (string) (floatval($existing_val) + floatval($new_val));
            } else { // max
                $result['value'] = (string) max(floatval($existing_val), floatval($new_val));
            }
            break;

        default:
            // For text, prefer longer value
            if (strlen($new['value'] ?? '') > strlen($existing['value'] ?? '')) {
                $result['value'] = $new['value'];
            }
            break;
    }

    return $result;
}

/**
 * Normalize customer feature aggregation mode.
 *
 * @param string $aggregation_mode Requested aggregation mode.
 * @return string
 */
function arraysubs_normalize_customer_feature_aggregation_mode(string $aggregation_mode): string
{
    $aggregation_mode = sanitize_text_field($aggregation_mode);

    if (in_array($aggregation_mode, ['sum', 'combine'], true)) {
        return 'combine';
    }

    if (in_array($aggregation_mode, ['per_product', 'per_subscription'], true)) {
        return 'per_subscription';
    }

    if (in_array($aggregation_mode, ['max', 'highest'], true)) {
        return 'max';
    }

    return 'combine';
}

/**
 * Get a specific feature value for a customer (aggregated)
 *
 * @param int    $customer_id  Customer ID.
 * @param string $feature_key  Feature name/key.
 * @param string $aggregation  Aggregation mode: 'sum', 'max', 'any'.
 * @return mixed Feature value or null if not found.
 */
function arraysubs_get_customer_feature_value(int $customer_id, string $feature_key, string $aggregation = 'sum')
{
    $evaluator = new \ArraySubs\Features\MembersAccess\Services\ConditionEvaluator();
    return $evaluator->getAggregatedFeatureValue($customer_id, $feature_key, $aggregation);
}

// ============================================================================
// FEATURE USAGE TRACKING FUNCTIONS
// ============================================================================

/**
 * Get usage data for a feature
 *
 * Usage is stored per subscription per feature in subscription meta:
 * _feature_usage_{feature_key} = ['used' => int, 'limit' => int|'unlimited', 'last_reset' => timestamp]
 *
 * @param int    $subscription_id Subscription ID.
 * @param string $feature_key     Feature name/key.
 * @return array Usage data with 'used', 'limit', 'remaining', 'percentage', 'is_unlimited' keys.
 */
function arraysubs_get_feature_usage(int $subscription_id, string $feature_key): array
{
    $meta_key = '_feature_usage_' . sanitize_key($feature_key);
    $usage_data = get_post_meta($subscription_id, $meta_key, true);

    // Get the feature limit from the product
    $product_id = get_post_meta($subscription_id, '_product_id', true);
    $variation_id = get_post_meta($subscription_id, '_variation_id', true);
    $target_id = $variation_id ?: $product_id;

    $feature = arraysubs_get_product_feature((int) $target_id, $feature_key);
    $limit = $feature['value'] ?? 0;

    // Default usage data
    $defaults = [
        'used'       => 0,
        'limit'      => $limit,
        'last_reset' => 0,
    ];

    if (!is_array($usage_data)) {
        $usage_data = $defaults;
    } else {
        $usage_data = wp_parse_args($usage_data, $defaults);
        // Update limit from product (in case it changed)
        $usage_data['limit'] = $limit;
    }

    // Calculate derived values
    $is_unlimited = strtolower((string) $usage_data['limit']) === 'unlimited';
    $limit_num = $is_unlimited ? PHP_INT_MAX : floatval($usage_data['limit']);
    $used = floatval($usage_data['used']);
    $remaining = $is_unlimited ? PHP_INT_MAX : max(0, $limit_num - $used);
    $percentage = ($is_unlimited || $limit_num <= 0) ? 0 : min(100, ($used / $limit_num) * 100);

    return [
        'used'         => $used,
        'limit'        => $usage_data['limit'],
        'remaining'    => $remaining,
        'percentage'   => round($percentage, 1),
        'is_unlimited' => $is_unlimited,
        'last_reset'   => $usage_data['last_reset'],
    ];
}

/**
 * Get aggregated feature usage for a customer across all subscriptions
 *
 * @param int    $customer_id  Customer ID.
 * @param string $feature_key  Feature name/key.
 * @return array Aggregated usage data.
 */
function arraysubs_get_customer_feature_usage(int $customer_id, string $feature_key): array
{
    $subscriptions = arraysubs_get_customer_subscriptions(
        $customer_id,
        ['arraysubs-active', 'arraysubs-trial']
    );

    $total_used = 0;
    $total_limit = 0;
    $is_unlimited = false;
    $per_subscription = [];

    foreach ($subscriptions as $subscription) {
        $subscription_id = arraysubs_get_normalized_subscription_id($subscription);

        if ($subscription_id <= 0) {
            continue;
        }

        $usage = arraysubs_get_feature_usage($subscription_id, $feature_key);

        // Skip if this subscription doesn't have this feature
        if ($usage['limit'] === 0 && $usage['used'] === 0) {
            continue;
        }

        $per_subscription[$subscription_id] = $usage;

        $total_used += $usage['used'];

        if ($usage['is_unlimited']) {
            $is_unlimited = true;
        } else {
            $total_limit += floatval($usage['limit']);
        }
    }

    $remaining = $is_unlimited ? PHP_INT_MAX : max(0, $total_limit - $total_used);
    $percentage = ($is_unlimited || $total_limit <= 0) ? 0 : min(100, ($total_used / $total_limit) * 100);

    return [
        'used'             => $total_used,
        'limit'            => $is_unlimited ? 'Unlimited' : $total_limit,
        'remaining'        => $remaining,
        'percentage'       => round($percentage, 1),
        'is_unlimited'     => $is_unlimited,
        'per_subscription' => $per_subscription,
    ];
}

/**
 * Update feature usage for a subscription
 *
 * @param int    $subscription_id Subscription ID.
 * @param string $feature_key     Feature name/key.
 * @param float  $used            New used value.
 * @return bool True on success.
 */
function arraysubs_update_feature_usage(int $subscription_id, string $feature_key, float $used): bool
{
    $meta_key = '_feature_usage_' . sanitize_key($feature_key);

    $current = arraysubs_get_feature_usage($subscription_id, $feature_key);

    $usage_data = [
        'used'       => max(0, $used),
        'limit'      => $current['limit'],
        'last_reset' => $current['last_reset'],
    ];

    return (bool) update_post_meta($subscription_id, $meta_key, $usage_data);
}

/**
 * Increment feature usage by a value
 *
 * @param int    $subscription_id Subscription ID.
 * @param string $feature_key     Feature name/key.
 * @param float  $increment       Amount to increment (can be negative).
 * @return array Updated usage data.
 */
function arraysubs_increment_feature_usage(int $subscription_id, string $feature_key, float $increment = 1): array
{
    $current = arraysubs_get_feature_usage($subscription_id, $feature_key);

    $new_used = max(0, $current['used'] + $increment);
    arraysubs_update_feature_usage($subscription_id, $feature_key, $new_used);

    return arraysubs_get_feature_usage($subscription_id, $feature_key);
}

/**
 * Reset feature usage for a subscription
 *
 * @param int    $subscription_id Subscription ID.
 * @param string $feature_key     Feature name/key.
 * @return bool True on success.
 */
function arraysubs_reset_feature_usage(int $subscription_id, string $feature_key): bool
{
    $meta_key = '_feature_usage_' . sanitize_key($feature_key);

    $current = arraysubs_get_feature_usage($subscription_id, $feature_key);

    $usage_data = [
        'used'       => 0,
        'limit'      => $current['limit'],
        'last_reset' => time(),
    ];

    return (bool) update_post_meta($subscription_id, $meta_key, $usage_data);
}

/**
 * Check if feature usage is within limit
 *
 * @param int    $subscription_id Subscription ID.
 * @param string $feature_key     Feature name/key.
 * @param float  $additional      Additional usage to check (optional).
 * @return bool True if within limit (or unlimited).
 */
function arraysubs_is_feature_usage_allowed(int $subscription_id, string $feature_key, float $additional = 0): bool
{
    $usage = arraysubs_get_feature_usage($subscription_id, $feature_key);

    if ($usage['is_unlimited']) {
        return true;
    }

    $total_after = $usage['used'] + $additional;

    return $total_after <= floatval($usage['limit']);
}

/**
 * Check if customer feature usage is within limit across all subscriptions
 *
 * @param int    $customer_id Customer ID.
 * @param string $feature_key Feature name/key.
 * @param float  $additional  Additional usage to check (optional).
 * @return bool True if within limit.
 */
function arraysubs_is_customer_feature_usage_allowed(int $customer_id, string $feature_key, float $additional = 0): bool
{
    $usage = arraysubs_get_customer_feature_usage($customer_id, $feature_key);

    if ($usage['is_unlimited']) {
        return true;
    }

    $total_after = $usage['used'] + $additional;

    return $total_after <= floatval($usage['limit']);
}

/**
 * Get all feature usages for a subscription
 *
 * @param int $subscription_id Subscription ID.
 * @return array Array of feature_key => usage_data.
 */
function arraysubs_get_all_feature_usages(int $subscription_id): array
{
    // Get the product features to know which features exist
    $product_id = get_post_meta($subscription_id, '_product_id', true);
    $variation_id = get_post_meta($subscription_id, '_variation_id', true);
    $target_id = $variation_id ?: $product_id;

    $features = arraysubs_get_product_features((int) $target_id);
    $usages = [];

    foreach ($features as $feature) {
        $feature_key = $feature['name'] ?? '';
        $type = $feature['type'] ?? 'text';

        // Only track usage for number type features
        if (empty($feature_key) || $type !== 'number') {
            continue;
        }

        $usages[$feature_key] = arraysubs_get_feature_usage($subscription_id, $feature_key);
    }

    return $usages;
}
