<?php

namespace Licenzo\Modules\WooCommerce;

use Licenzo\Helper\Settings;

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

class WooSubscriptionCheckoutPolicyService
{
    /**
     * @var WooStripeCompatibilityService
     */
    private $stripeCompatibility;

    public function __construct(?WooStripeCompatibilityService $stripeCompatibility = null)
    {
        $this->stripeCompatibility = $stripeCompatibility ?? new WooStripeCompatibilityService();
    }

    public function register(): void
    {
        if (!class_exists('WooCommerce')) {
            return;
        }

        add_filter('woocommerce_add_to_cart_validation', [$this, 'enforceSingleSubscriptionItemInCart'], 20, 6);
        add_filter('woocommerce_update_cart_validation', [$this, 'enforceSingleSubscriptionItemQuantityUpdate'], 20, 4);

        add_action('woocommerce_checkout_process', [$this, 'validateGuestCheckout'], 5);
        add_action('woocommerce_checkout_process', [$this, 'requireAccountCreation'], 15);

        // Manual renewal notice support is wired for renewal cart markers when manual flow is introduced.
        add_action('woocommerce_before_cart', [$this, 'maybeRenderManualRenewalCartNotice'], 5);
        add_action('woocommerce_before_checkout_form', [$this, 'maybeRenderManualRenewalCartNotice'], 5);
    }

    public function enforceSingleSubscriptionItemInCart(
        $passed,
        $productId,
        $quantity,
        $variationId = 0,
        $variations = [],
        $cartItemData = []
    ) {
        if (!$passed) {
            return false;
        }

        $productId = (int) $productId;
        $variationId = (int) $variationId;

        if (!$this->isRecurringMappedSubscriptionProduct($productId, $variationId)) {
            return $passed;
        }

        $requestedQuantity = max(1, (int) $quantity);
        $existingSubscriptionQuantity = $this->getRecurringSubscriptionQuantityInCart();

        if (($existingSubscriptionQuantity + $requestedQuantity) <= 1) {
            return $passed;
        }

        $this->addCheckoutErrorNotice(
            __('Only one subscription item can be in cart right now. Please checkout the existing subscription item first.', 'licenzo')
        );

        return false;
    }

    public function enforceSingleSubscriptionItemQuantityUpdate($passed, $cartItemKey, $values, $quantity)
    {
        if (!$passed || !is_array($values)) {
            return $passed;
        }

        $productId = isset($values['product_id']) ? (int) $values['product_id'] : 0;
        $variationId = isset($values['variation_id']) ? (int) $values['variation_id'] : 0;

        if (!$this->isRecurringMappedSubscriptionProduct($productId, $variationId)) {
            return $passed;
        }

        $requestedQuantity = max(0, (int) $quantity);
        if ($requestedQuantity === 0) {
            return $passed;
        }

        $otherSubscriptionQuantity = $this->getRecurringSubscriptionQuantityInCart((string) $cartItemKey);
        if (($otherSubscriptionQuantity + $requestedQuantity) <= 1) {
            return $passed;
        }

        $this->addCheckoutErrorNotice(
            __('Only one subscription item can be in cart right now. Please checkout the existing subscription item first.', 'licenzo')
        );

        return false;
    }

    public function validateGuestCheckout(): void
    {
        if (!$this->isRecurringSubscriptionCart() || is_user_logged_in()) {
            return;
        }

        if ($this->isGuestCheckoutAllowed()) {
            return;
        }

        $this->addCheckoutErrorNotice(
            __('You are trying to buy a subscription. You must be logged in to continue.', 'licenzo')
        );
    }

    public function requireAccountCreation(): void
    {
        if (!$this->isRecurringSubscriptionCart() || is_user_logged_in()) {
            return;
        }

        if (!$this->isGuestCheckoutAllowed() || !$this->isGuestLoginEnforced()) {
            return;
        }

        $createAccount = false;
        if (isset($_POST['createaccount'])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
            $raw = strtolower(sanitize_text_field(wp_unslash($_POST['createaccount']))); // phpcs:ignore WordPress.Security.NonceVerification.Missing
            $createAccount = in_array($raw, ['1', 'true', 'yes', 'on'], true);
        }

        if ($createAccount) {
            return;
        }

        $this->addCheckoutErrorNotice(
            __('You are trying to buy a subscription. Please log in or select "Create an account" to continue.', 'licenzo')
        );
    }

    public function maybeRenderManualRenewalCartNotice(): void
    {
        if (!$this->isManualRenewalProcess()) {
            return;
        }

        if (!$this->cartHasManualRenewalMarker()) {
            return;
        }

        $settings = Settings::getSubscriptionSettings();
        $notice = trim((string) ($settings['manual_renew_cart_notice'] ?? ''));
        if ($notice === '') {
            return;
        }

        if (function_exists('wc_print_notice')) {
            wc_print_notice(wp_kses_post($notice), 'notice');
        }
    }

    private function isRecurringSubscriptionCart(): bool
    {
        return $this->stripeCompatibility->cartHasRecurringLicenzoSubscriptionItems();
    }

    private function isRecurringMappedSubscriptionProduct(int $productId, int $variationId): bool
    {
        return $this->stripeCompatibility->isRecurringMappedProductInLicenzo($productId, $variationId);
    }

    private function isGuestCheckoutAllowed(): bool
    {
        $settings = Settings::getSubscriptionSettings();
        return (($settings['allow_guest_checkout'] ?? 'no') === 'yes');
    }

    private function isGuestLoginEnforced(): bool
    {
        $settings = Settings::getSubscriptionSettings();
        return (($settings['enforce_login'] ?? 'yes') === 'yes');
    }

    private function isManualRenewalProcess(): bool
    {
        $settings = Settings::getSubscriptionSettings();
        return (($settings['renewal_process'] ?? 'auto') === 'manual');
    }

    private function cartHasManualRenewalMarker(): bool
    {
        if (!function_exists('WC') || !WC() || !WC()->cart) {
            return false;
        }

        $items = WC()->cart->get_cart();
        if (!is_array($items)) {
            return false;
        }

        foreach ($items as $cartItem) {
            if (!is_array($cartItem)) {
                continue;
            }

            if (!empty($cartItem['licenzo_manual_renewal']) || !empty($cartItem['licenzo_renewal_order'])) {
                return true;
            }

            if (!empty($cartItem['licenzo_subscription_id']) || !empty($cartItem['_licenzo_subscription_id'])) {
                return true;
            }
        }

        return false;
    }

    private function getRecurringSubscriptionQuantityInCart(string $excludeCartItemKey = ''): int
    {
        if (!function_exists('WC') || !WC() || !WC()->cart) {
            return 0;
        }

        $items = WC()->cart->get_cart();
        if (!is_array($items)) {
            return 0;
        }

        $quantity = 0;

        foreach ($items as $cartItemKey => $cartItem) {
            if ($excludeCartItemKey !== '' && (string) $cartItemKey === $excludeCartItemKey) {
                continue;
            }

            if (!is_array($cartItem)) {
                continue;
            }

            $productId = isset($cartItem['product_id']) ? (int) $cartItem['product_id'] : 0;
            $variationId = isset($cartItem['variation_id']) ? (int) $cartItem['variation_id'] : 0;

            if (!$this->isRecurringMappedSubscriptionProduct($productId, $variationId)) {
                continue;
            }

            $quantity += max(0, (int) ($cartItem['quantity'] ?? 1));
        }

        return $quantity;
    }

    private function addCheckoutErrorNotice(string $message): void
    {
        if (!function_exists('wc_add_notice')) {
            return;
        }

        if (function_exists('wc_has_notice') && wc_has_notice($message, 'error')) {
            return;
        }

        wc_add_notice($message, 'error');
    }
}
