<?php

/**
 * Purchase History Service
 *
 * Service to query customer purchase history from WooCommerce.
 * Used by the Condition Evaluator to check purchase-based conditions.
 *
 * @package ArraySubs\Features\MembersAccess\Services
 * @since 1.0.0
 */

namespace ArraySubs\Features\MembersAccess\Services;

defined('ABSPATH') || exit;

/**
 * PurchaseHistory class
 */
class PurchaseHistory
{
    /**
     * Cache key prefix
     *
     * @var string
     */
    private const CACHE_PREFIX = 'arraysubs_purchase_history_';

    /**
     * Cache expiration in seconds (1 hour)
     *
     * @var int
     */
    private const CACHE_EXPIRATION = 3600;

    /**
     * Get customer's lifetime spent amount
     *
     * @param int $user_id User ID.
     * @return float
     */
    public function getLifetimeSpent(int $user_id): float
    {
        if (!function_exists('wc_get_customer_total_spent')) {
            return 0.0;
        }

        // Use WooCommerce's built-in function
        return (float) wc_get_customer_total_spent($user_id);
    }

    /**
     * Check if customer 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
     */
    public function hasPurchasedProduct(int $user_id, int $product_id, bool $include_variations = true): bool
    {
        if (!function_exists('wc_customer_bought_product')) {
            return false;
        }

        // Get user email for WooCommerce function
        $user = get_userdata($user_id);
        if (!$user) {
            return false;
        }

        $user_email = $user->user_email;

        // Direct check using WooCommerce
        if (wc_customer_bought_product($user_email, $user_id, $product_id)) {
            return true;
        }

        // If checking variations, also check if the product_id is a parent
        // and any of its variations were purchased
        if ($include_variations) {
            $product = wc_get_product($product_id);
            if ($product && $product->is_type('variable')) {
                $variation_ids = $product->get_children();
                foreach ($variation_ids as $variation_id) {
                    if (wc_customer_bought_product($user_email, $user_id, $variation_id)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * Check if customer has purchased a specific variation
     *
     * @param int $user_id      User ID.
     * @param int $variation_id Variation ID.
     * @return bool
     */
    public function hasPurchasedVariation(int $user_id, int $variation_id): bool
    {
        if (!function_exists('wc_customer_bought_product')) {
            return false;
        }

        $user = get_userdata($user_id);
        if (!$user) {
            return false;
        }

        return wc_customer_bought_product($user->user_email, $user_id, $variation_id);
    }

    /**
     * Get all product IDs the customer has purchased
     *
     * Uses WooCommerce's HPOS-compatible functions for order queries.
     *
     * @param int $user_id User ID.
     * @return array Array of product IDs.
     */
    public function getPurchasedProductIds(int $user_id): array
    {
        $cache_key = self::CACHE_PREFIX . 'products_' . $user_id;
        $cached = get_transient($cache_key);

        if ($cached !== false) {
            return $cached;
        }

        if (!function_exists('wc_get_orders')) {
            return [];
        }

        // Get all completed/processing orders for the user using HPOS-compatible function
        $orders = wc_get_orders([
            'customer_id' => $user_id,
            'status'      => ['completed', 'processing'],
            'limit'       => -1,
            'return'      => 'ids',
        ]);

        if (empty($orders)) {
            set_transient($cache_key, [], self::CACHE_EXPIRATION);
            return [];
        }

        $all_product_ids = [];

        foreach ($orders as $order_id) {
            $order = wc_get_order($order_id);
            if (!$order) {
                continue;
            }

            foreach ($order->get_items() as $item) {
                $product_id = $item->get_product_id();
                $variation_id = $item->get_variation_id();

                if ($product_id > 0) {
                    $all_product_ids[] = $product_id;
                }
                if ($variation_id > 0) {
                    $all_product_ids[] = $variation_id;
                }
            }
        }

        $all_ids = array_unique(array_map('absint', $all_product_ids));

        set_transient($cache_key, $all_ids, self::CACHE_EXPIRATION);

        return $all_ids;
    }

    /**
     * Check if customer has purchased any product from a taxonomy group
     *
     * @param int    $user_id  User ID.
     * @param string $taxonomy Taxonomy slug (e.g., 'product_cat', 'product_tag').
     * @param array  $term_ids Term IDs to check.
     * @return bool
     */
    public function hasPurchasedFromGroup(int $user_id, string $taxonomy, array $term_ids): bool
    {
        if (empty($term_ids)) {
            return false;
        }

        $purchased_product_ids = $this->getPurchasedProductIds($user_id);

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

        // Check if any purchased product belongs to the specified terms
        foreach ($purchased_product_ids as $product_id) {
            // Get the parent product ID if this is a variation
            $product = wc_get_product($product_id);
            if (!$product) {
                continue;
            }

            $check_product_id = $product_id;
            if ($product->is_type('variation')) {
                $check_product_id = $product->get_parent_id();
            }

            // Check if product has any of the specified terms
            $product_terms = wp_get_object_terms($check_product_id, $taxonomy, ['fields' => 'ids']);
            if (!is_wp_error($product_terms)) {
                $intersection = array_intersect($product_terms, $term_ids);
                if (!empty($intersection)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Get purchase count for a user
     *
     * @param int $user_id User ID.
     * @return int
     */
    public function getPurchaseCount(int $user_id): int
    {
        if (!function_exists('wc_get_customer_order_count')) {
            return 0;
        }

        return (int) wc_get_customer_order_count($user_id);
    }

    /**
     * Check if customer has purchased a specific product a minimum number of times
     *
     * Uses WooCommerce's HPOS-compatible order queries.
     *
     * @param int $user_id    User ID.
     * @param int $product_id Product ID.
     * @param int $min_count  Minimum purchase count.
     * @return bool
     */
    public function hasPurchasedProductTimes(int $user_id, int $product_id, int $min_count = 1): bool
    {
        if (!function_exists('wc_get_orders')) {
            return false;
        }

        // Get all completed/processing orders for the user
        $orders = wc_get_orders([
            'customer_id' => $user_id,
            'status'      => ['completed', 'processing'],
            'limit'       => -1,
            'return'      => 'ids',
        ]);

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

        $count = 0;

        foreach ($orders as $order_id) {
            $order = wc_get_order($order_id);
            if (!$order) {
                continue;
            }

            foreach ($order->get_items() as $item) {
                $item_product_id = $item->get_product_id();
                $item_variation_id = $item->get_variation_id();

                if ($item_product_id === $product_id || $item_variation_id === $product_id) {
                    ++$count;
                    break; // Only count once per order
                }
            }

            // Early exit if we already reached min_count
            if ($count >= $min_count) {
                return true;
            }
        }

        return $count >= $min_count;
    }

    /**
     * Clear purchase history cache for a user
     *
     * @param int $user_id User ID.
     * @return void
     */
    public function clearCache(int $user_id): void
    {
        delete_transient(self::CACHE_PREFIX . 'products_' . $user_id);
    }

    /**
     * Clear cache when order status changes
     *
     * @param int $order_id Order ID.
     * @return void
     */
    public static function onOrderStatusChanged(int $order_id): void
    {
        $order = wc_get_order($order_id);
        if (!$order) {
            return;
        }

        $user_id = $order->get_customer_id();
        if ($user_id > 0) {
            delete_transient(self::CACHE_PREFIX . 'products_' . $user_id);
        }
    }
}
