<?php

/**
 * Cart Validation Service
 *
 * @package ArraySubs\Features\SubscriptionCheckout\Services
 */

namespace ArraySubs\Features\SubscriptionCheckout\Services;

defined('ABSPATH') || exit;

/**
 * Validate cart items for subscription products
 */
class CartValidation
{
    /**
     * Enable auto-loading
     *
     * @var bool
     */
    public static $loadable = true;

    /**
     * Constructor
     */
    public function __construct()
    {
        add_action('woocommerce_check_cart_items', [$this, 'validateCart']);
        add_action('woocommerce_store_api_cart_errors', [$this, 'validateCartStoreApi'], 10, 2);
    }

    /**
     * Validate cart items (classic cart page)
     */
    public function validateCart(): void
    {
        foreach ($this->getCartValidationErrors() as $error) {
            wc_add_notice($error, 'error');
        }
    }

    /**
     * Validate cart items for Store API (Block Cart / Checkout)
     *
     * @param \WP_Error $errors WP_Error instance to add errors to.
     * @param \WC_Cart  $cart   Cart object.
     */
    public function validateCartStoreApi(\WP_Error $errors, \WC_Cart $cart): void
    {
        foreach ($this->getCartValidationErrors() as $error) {
            $errors->add('arraysubs_cart_error', $error);
        }
    }

    /**
     * Collect cart validation error messages.
     *
     * @return string[]
     */
    private function getCartValidationErrors(): array
    {
        $cart = WC()->cart;

        if (!$cart) {
            return [];
        }

        $errors = [];
        $subscription_count = 0;
        $regular_count = 0;
        $subscription_products = [];
        $subscription_quantities = [];
        $distinct_subscription_products = [];

        if (WC()->session && WC()->session->get('arraysubs_single_product_quantity_error')) {
            $errors[] = $this->getSingleProductQuantityMessage();
            WC()->session->__unset('arraysubs_single_product_quantity_error');
        }

        // Count subscription vs regular products
        foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
            $product_id = $cart_item['product_id'];
            $variation_id = $cart_item['variation_id'] ?? 0;
            $check_id = $variation_id > 0 ? $variation_id : $product_id;

            if (arraysubs_is_subscription_product($check_id)) {
                ++$subscription_count;
                $subscription_products[] = $cart_item;
                $subscription_quantities[$check_id] = ($subscription_quantities[$check_id] ?? 0) + max(1, absint($cart_item['quantity'] ?? 1));
                $distinct_subscription_products[$check_id] = true;
            } else {
                ++$regular_count;
            }
        }

        // No subscriptions, nothing to validate
        if ($subscription_count === 0) {
            return [];
        }

        // Check if multiple subscriptions are allowed
        $allow_multiple_default = (bool) arraysubs_get_setting('multiple_subscriptions.allow_multiple_in_cart', true);
        $allow_multiple         = apply_filters('arraysubs_allow_multiple_subscriptions', $allow_multiple_default);

        if (!$allow_multiple && count($distinct_subscription_products) > 1) {
            $errors[] = $this->getMultipleSubscriptionsCartRestrictionMessage();
        }

        // One subscription per customer: only one distinct subscription allowed in cart
        if (
            function_exists('arraysubs_is_one_subscription_per_customer')
            && arraysubs_is_one_subscription_per_customer()
            && count($distinct_subscription_products) > 1
        ) {
            $errors[] = $this->getOneSubscriptionPerCustomerCartMessage();
        }

        // Mixed cart check
        $allow_mixed_default = (bool) arraysubs_get_setting('multiple_subscriptions.allow_mixed_cart', true);
        $allow_mixed_cart    = apply_filters('arraysubs_allow_mixed_cart', $allow_mixed_default);

        if (!$allow_mixed_cart && $subscription_count > 0 && $regular_count > 0) {
            $errors[] = $this->getMixedCartRestrictionMessage();
        }

        if (function_exists('arraysubs_is_one_subscription_per_product') && arraysubs_is_one_subscription_per_product()) {
            foreach ($subscription_quantities as $product_id => $quantity) {
                if ($quantity > 1) {
                    $errors[] = $this->getSingleProductQuantityMessage();
                    break;
                }
            }
        }

        if (function_exists('arraysubs_is_one_trial_per_customer') && arraysubs_is_one_trial_per_customer()) {
            $trial_quantity = 0;

            foreach ($subscription_quantities as $product_id => $quantity) {
                if (!function_exists('arraysubs_product_has_free_trial') || !arraysubs_product_has_free_trial((int) $product_id)) {
                    continue;
                }

                $trial_quantity += $quantity;

                if ($trial_quantity > 1) {
                    $errors[] = $this->getTrialCartValidationMessage();
                    break;
                }
            }
        }

        // Different billing cycles check
        if ($subscription_count > 1) {
            $allow_different_default = (bool) arraysubs_get_setting('multiple_subscriptions.allow_different_cycles', true);
            $allow_different_cycles  = apply_filters('arraysubs_allow_different_billing_cycles', $allow_different_default);

            if (!$allow_different_cycles) {
                $cycles = [];
                foreach ($subscription_products as $cart_item) {
                    $item_product_id = $cart_item['product_id'];
                    $item_variation  = $cart_item['variation_id'] ?? 0;
                    $item_check_id   = $item_variation > 0 ? $item_variation : $item_product_id;

                    $sub_data = arraysubs_get_product_subscription_data($item_check_id);
                    if ($sub_data) {
                        $cycle_key = $sub_data['period'] . ':' . $sub_data['interval'];
                        $cycles[$cycle_key] = true;
                    }
                }

                if (count($cycles) > 1) {
                    $errors[] = $this->getDifferentBillingCyclesRestrictionMessage();
                }
            }
        }

        // Validate each subscription product
        foreach ($subscription_products as $cart_item) {
            $product_id = $cart_item['product_id'];
            $variation_id = $cart_item['variation_id'] ?? 0;
            $check_id = $variation_id > 0 ? $variation_id : $product_id;

            $subscription_data = arraysubs_get_product_subscription_data($check_id);

            if (!$subscription_data || empty($subscription_data['price'])) {
                $errors[] = __('One or more subscription products have invalid pricing. Please contact support.', 'arraysubs');
            }
        }

        return $errors;
    }

    /**
     * Get the cart validation message for one-per-product enforcement.
     *
     * @return string
     */
    private function getSingleProductQuantityMessage(): string
    {
        return __('One Subscription per Product is enabled. Each subscription product can appear only once per order, so reduce the quantity to 1 before continuing.', 'arraysubs');
    }

    /**
     * Get the cart validation message for mixed-cart enforcement.
     *
     * @return string
     */
    private function getMixedCartRestrictionMessage(): string
    {
        return __('Mixed carts are disabled for subscriptions. Remove either the subscription product or the regular product before continuing.', 'arraysubs');
    }

    /**
     * Get the cart validation message for multiple subscription plan enforcement.
     *
     * @return string
     */
    private function getMultipleSubscriptionsCartRestrictionMessage(): string
    {
        return __('Multiple subscription plans are disabled for one checkout. Keep only one subscription plan in the cart, then place a separate order for any other plan.', 'arraysubs');
    }

    /**
     * Get the cart validation message for one-subscription-per-customer enforcement.
     *
     * @return string
     */
    private function getOneSubscriptionPerCustomerCartMessage(): string
    {
        return __('One Subscription per Customer is enabled. Keep only one subscription plan in the cart; if the customer already has a live subscription, manage that subscription or switch to an allowed target plan.', 'arraysubs');
    }

    /**
     * Get the cart validation message for trial quantity enforcement.
     *
     * @return string
     */
    private function getTrialCartValidationMessage(): string
    {
        return __('One Trial per Customer is enabled. Keep only one trial subscription in the cart and reduce its quantity to 1 before continuing.', 'arraysubs');
    }

    /**
     * Get the cart validation message for different billing cycle enforcement.
     *
     * @return string
     */
    private function getDifferentBillingCyclesRestrictionMessage(): string
    {
        return __('Different billing cycles are disabled for one checkout. Keep subscription plans with the same billing cycle in the cart, or place separate orders.', 'arraysubs');
    }
}
