<?php

namespace Licenzo\Modules\WooCommerce;

use Licenzo\Helper\Settings;
use Licenzo\Model\Product;
use Licenzo\Model\ProductVariation;
use Licenzo\Services\Integrations\ProviderAliasService;

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

class WooStripeCompatibilityService
{
    public const SUPPORTED_METHODS = ['stripe', 'stripe_ideal', 'stripe_sepa', 'sepa_debit', 'stripe_bancontact'];

    public const MANDATE_NEEDED_METHODS = ['stripe_ideal', 'stripe_sepa', 'sepa_debit', 'stripe_bancontact'];

    /**
     * Small in-request cache for provider-id lookups.
     *
     * @var array<string,bool>
     */
    private $recurringProductCache = [];

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

        add_filter('wc_stripe_payment_metadata', [$this, 'addPaymentMetadata'], 10, 2);
        add_filter('wc_stripe_force_save_payment_method', [$this, 'forceSavePaymentMethodForSubscriptions'], 10, 2);
        add_filter('wc_stripe_generate_create_intent_request', [$this, 'modifyCreateIntentRequestForSubscriptions'], 20, 3);
    }

    public function forceSavePaymentMethodForSubscriptions($force, $orderId = 0)
    {
        if (!$this->isStripeAutoRenewEnabled()) {
            return $force;
        }

        if ($this->cartHasRecurringLicenzoSubscriptionItems()) {
            return true;
        }

        if ($orderId && $this->orderHasRecurringLicenzoSubscriptionItems((int) $orderId)) {
            return true;
        }

        return $force;
    }

    public function modifyCreateIntentRequestForSubscriptions($request, $order, $preparedSource)
    {
        if (!is_array($request) || !$order || !method_exists($order, 'get_id')) {
            return $request;
        }

        $orderId = (int) $order->get_id();
        if (!$this->orderHasRecurringLicenzoSubscriptionItems($orderId)) {
            return $request;
        }

        if (!$this->isStripeAutoRenewEnabled() && !$this->isLizenzoRenewalOrder($order)) {
            return $request;
        }

        $request['metadata'] = isset($request['metadata']) && is_array($request['metadata'])
            ? $request['metadata']
            : [];

        if ($this->isLizenzoRenewalOrder($order)) {
            unset($request['setup_future_usage']);
            $request['metadata']['payment_type'] = 'recurring';
        } else {
            $request['setup_future_usage'] = 'off_session';
            $request['metadata']['save_payment_method'] = 'true';
        }

        $customerId = $this->readObjectProperty($preparedSource, 'customer');
        if (!empty($customerId)) {
            $request['customer'] = $customerId;
        }

        if (
            isset($request['confirm']) &&
            true === $request['confirm'] &&
            in_array((string) $order->get_payment_method(), static::MANDATE_NEEDED_METHODS, true)
        ) {
            $request['mandate_data'] = [
                'customer_acceptance' => [
                    'type' => 'offline',
                ],
            ];
        }

        return $request;
    }

    public function addPaymentMetadata(array $metadata, $order): array
    {
        if (!$order || !method_exists($order, 'get_id')) {
            return $metadata;
        }

        if (!$this->orderHasRecurringLicenzoSubscriptionItems((int) $order->get_id())) {
            return $metadata;
        }

        $metadata['licenzo_subscription'] = '1';

        if ($this->isLizenzoRenewalOrder($order)) {
            $metadata['payment_type'] = 'recurring';

            $subscriptionId = (int) $order->get_meta('_licenzo_subscription_id', true);
            if ($subscriptionId > 0) {
                $metadata['licenzo_subscription_id'] = (string) $subscriptionId;
            }
        }

        return $metadata;
    }

    public function isStripeAutoRenewCapableOrder($order): bool
    {
        if (!$order || !method_exists($order, 'get_payment_method')) {
            return false;
        }

        $method = (string) $order->get_payment_method();
        $isStripeMethod = $method !== '' && in_array($method, static::SUPPORTED_METHODS, true);

        $hasStripeMeta = false;
        if (method_exists($order, 'get_meta')) {
            $hasStripeMeta = (string) $order->get_meta('_stripe_customer_id', true) !== ''
                || (string) $order->get_meta('_stripe_source_id', true) !== ''
                || (string) $order->get_meta('_stripe_card_id', true) !== ''
                || (string) $order->get_meta('_stripe_mandate_id', true) !== '';
        }

        return $isStripeMethod || $hasStripeMeta;
    }

    private function isStripeAvailable(): bool
    {
        return function_exists('woocommerce_gateway_stripe') && class_exists('WC_Stripe');
    }

    public function cartHasRecurringLicenzoSubscriptionItems(): 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) {
            $productId = isset($cartItem['product_id']) ? (int) $cartItem['product_id'] : 0;
            $variationId = isset($cartItem['variation_id']) ? (int) $cartItem['variation_id'] : 0;

            if ($this->isRecurringMappedProduct($productId, $variationId)) {
                return true;
            }
        }

        return false;
    }

    public function orderHasRecurringLicenzoSubscriptionItems(int $orderId): bool
    {
        if ($orderId <= 0 || !function_exists('wc_get_order')) {
            return false;
        }

        $order = wc_get_order($orderId);
        if (!$order) {
            return false;
        }

        if ($this->isLizenzoRenewalOrder($order)) {
            return true;
        }

        foreach ($order->get_items() as $item) {
            if ($this->isRecurringMappedProduct((int) $item->get_product_id(), (int) $item->get_variation_id())) {
                return true;
            }
        }

        return false;
    }

    public function isRecurringMappedProductInLicenzo(int $productId, int $variationId): bool
    {
        return $this->isRecurringMappedProduct($productId, $variationId);
    }

    private function isRecurringMappedProduct(int $productId, int $variationId): bool
    {
        if ($productId <= 0 && $variationId <= 0) {
            return false;
        }

        $cacheKey = $productId . ':' . $variationId;
        if (array_key_exists($cacheKey, $this->recurringProductCache)) {
            return $this->recurringProductCache[$cacheKey];
        }

        $query = Product::whereIn('provider', $this->getWooProviderAliases());

        $mapped = $query->where(function ($q) use ($productId, $variationId) {
            if ($productId > 0 && $variationId > 0) {
                $q->where('provider_id', (string) $productId);
                $q->orWhereHas('variations', function ($variationQuery) use ($variationId) {
                    $variationQuery->where('provider_id', (string) $variationId);
                });
                return;
            }

            if ($productId > 0) {
                $q->where('provider_id', (string) $productId);
                return;
            }

            if ($variationId > 0) {
                $q->whereHas('variations', function ($variationQuery) use ($variationId) {
                    $variationQuery->where('provider_id', (string) $variationId);
                });
            }
        })->with('variations')->first();

        if (!$mapped) {
            return $this->recurringProductCache[$cacheKey] = false;
        }

        $variation = $variationId > 0
            ? $mapped->variations->firstWhere('provider_id', (string) $variationId)
            : $mapped->variations->first();

        if (!$variation) {
            return $this->recurringProductCache[$cacheKey] = false;
        }

        $cycle = $variation->billing_cycle ?? null;

        return $this->recurringProductCache[$cacheKey] = $this->isRecurringCycle($cycle);
    }

    private function isRecurringCycle(?string $cycle): bool
    {
        return !in_array((string) $cycle, [
            ProductVariation::PRICE_CYCLE_ONETIME,
            ProductVariation::PRICE_CYCLE_LIFETIME,
            '',
        ], true);
    }

    /**
     * Provider aliases used in mapped Woo product records.
     *
     * @return array<int,string>
     */
    private function getWooProviderAliases(): array
    {
        return ProviderAliasService::wooAliases();
    }

    private function isLizenzoRenewalOrder($order): bool
    {
        if (!$order || !method_exists($order, 'get_meta')) {
            return false;
        }

        $flag = $order->get_meta('_licenzo_renewal_order', true);
        return in_array($flag, [1, '1', true, 'true', 'yes'], true);
    }

    private function readObjectProperty($object, string $property)
    {
        if (is_object($object) && isset($object->{$property})) {
            return $object->{$property};
        }

        return null;
    }

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