<?php

/**
 * Checkout Helpers Trait
 *
 * Shared utility methods used across multiple checkout traits.
 *
 * @package ArraySubs\Features\SubscriptionCheckout\Services\Traits
 */

namespace ArraySubs\Features\SubscriptionCheckout\Services\Traits;

defined('ABSPATH') || exit;

/**
 * Shared checkout helper methods
 */
trait CheckoutHelpersTrait
{
    /**
     * Maybe require registration for subscription purchases
     * If cart contains subscription and auto_create_account is enabled, require registration
     *
     * @param bool $required Current registration requirement
     * @return bool Modified requirement
     */
    public function maybeRequireRegistration(bool $required): bool
    {
        // If already required or user already logged in, don't change
        if ($required || is_user_logged_in()) {
            return $required;
        }

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

        return $required;
    }

    /**
     * Enable checkout registration when subscription checkout requires an account.
     *
     * @param bool $enabled Current registration-enabled value.
     * @return bool
     */
    public function maybeEnableRegistrationForSubscriptionCheckout(bool $enabled): bool
    {
        if ($enabled || is_user_logged_in()) {
            return $enabled;
        }

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

        return $enabled;
    }

    /**
     * Require a customer-entered password for forced subscription account creation.
     *
     * @param array<string,array<string,mixed>> $fields Checkout fields.
     * @return array<string,array<string,mixed>>
     */
    public function maybeAddAccountPasswordFieldForSubscriptionCheckout(array $fields): array
    {
        if (is_user_logged_in() || !$this->shouldForceAccountCreationForSubscriptionCheckout()) {
            return $fields;
        }

        if (!isset($fields['account']) || !is_array($fields['account'])) {
            $fields['account'] = [];
        }

        $fields['account']['account_password'] = array_merge(
            [
                'type'         => 'password',
                'label'        => __('Create account password', 'arraysubs'),
                'required'     => true,
                'placeholder'  => __('Password', 'arraysubs'),
                'autocomplete' => 'new-password',
                'priority'     => 20,
            ],
            $fields['account']['account_password'] ?? []
        );
        $fields['account']['account_password']['required'] = true;

        return $fields;
    }

    /**
     * Check whether checkout should force a visible account creation flow.
     *
     * @return bool
     */
    private function shouldForceAccountCreationForSubscriptionCheckout(): bool
    {
        return function_exists('arraysubs_is_auto_create_account_enabled')
            && arraysubs_is_auto_create_account_enabled()
            && $this->cartHasSubscriptionCheckoutItems();
    }

    /**
     * Remove cash on delivery when the cart contains subscription checkout items.
     *
     * WooCommerce uses the same available-gateways pipeline for classic checkout,
     * checkout blocks, and Store API checkout sessions, so removing COD here keeps
     * the gateway hidden consistently whenever subscription-style checkout behavior
     * is active.
     *
     * @param array<string, \WC_Payment_Gateway> $available_gateways Available payment gateways.
     * @return array<string, \WC_Payment_Gateway>
     */
    public function maybeHideCashOnDeliveryForSubscriptionCheckout(array $available_gateways): array
    {
        if (empty($available_gateways['cod'])) {
            return $available_gateways;
        }

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

        unset($available_gateways['cod']);

        return $available_gateways;
    }

    /**
     * Hide unsupported automatic gateways when renewal sync is active for the cart.
     *
     * @param array<string, \WC_Payment_Gateway> $available_gateways Available payment gateways.
     * @return array<string, \WC_Payment_Gateway>
     */
    public function maybeHideUnsupportedRenewalSyncGateways(array $available_gateways): array
    {
        if (!$this->cartHasRenewalSyncCheckoutItems()) {
            return $available_gateways;
        }

        if (!function_exists('arraysubs_is_renewal_sync_supported_gateway')) {
            return $available_gateways;
        }

        foreach ($available_gateways as $gateway_id => $gateway) {
            if (!arraysubs_is_renewal_sync_supported_gateway((string) $gateway_id, $gateway)) {
                unset($available_gateways[$gateway_id]);
            }
        }

        return $available_gateways;
    }

    /**
     * Validate classic checkout gateway support for synced renewal signup pricing.
     *
     * @param array     $data   Posted checkout data.
     * @param \WP_Error $errors Checkout validation errors.
     * @return void
     */
    public function validateRenewalSyncGatewaySupport(array $data, \WP_Error $errors): void
    {
        if (!$this->cartHasRenewalSyncCheckoutItems()) {
            return;
        }

        $gateway_id = sanitize_key((string) ($data['payment_method'] ?? ''));
        if ('' === $gateway_id && isset($_POST['payment_method'])) {
            $gateway_id = sanitize_key(wp_unslash((string) $_POST['payment_method']));
        }

        if ($this->renewalSyncGatewayIsSupported($gateway_id)) {
            return;
        }

        $errors->add(
            'arraysubs_renewal_sync_gateway',
            __('Renewal sync is available for manual payment gateways and Stripe only. Choose a supported payment method to continue.', 'arraysubs')
        );
    }

    /**
     * Validate Store API checkout gateway support for synced renewal signup pricing.
     *
     * @param \WC_Order $order  Order object.
     * @param \WP_Error $errors Validation errors.
     * @return void
     */
    public function validateRenewalSyncGatewaySupportStoreApi($order, \WP_Error $errors): void
    {
        if (!$this->cartHasRenewalSyncCheckoutItems() || !$order instanceof \WC_Order) {
            return;
        }

        if ($this->renewalSyncGatewayIsSupported((string) $order->get_payment_method())) {
            return;
        }

        $errors->add(
            'arraysubs_renewal_sync_gateway',
            __('Renewal sync is available for manual payment gateways and Stripe only. Choose a supported payment method to continue.', 'arraysubs')
        );
    }

    /**
     * Check whether the current cart contains subscription checkout items.
     *
     * This uses the shared checkout-behavior helper so addon-defined items can
     * opt into the same restrictions without duplicating core gateway logic.
     *
     * @return bool
     */
    private function cartHasSubscriptionCheckoutItems(): bool
    {
        if (!function_exists('WC') || !WC()->cart || !function_exists('arraysubs_is_subscription_checkout_product')) {
            return false;
        }

        foreach (WC()->cart->get_cart() as $cart_item) {
            $product_id = !empty($cart_item['variation_id']) && $cart_item['variation_id'] > 0
                ? (int) $cart_item['variation_id']
                : (int) ($cart_item['product_id'] ?? 0);

            if ($product_id > 0 && arraysubs_is_subscription_checkout_product($product_id)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check whether the current cart has subscription items eligible for renewal sync.
     *
     * @return bool
     */
    private function cartHasRenewalSyncCheckoutItems(): bool
    {
        if (
            !function_exists('WC')
            || !WC()->cart
            || !function_exists('arraysubs_get_product_subscription_data')
            || !function_exists('arraysubs_subscription_data_supports_renewal_sync')
        ) {
            return false;
        }

        foreach (WC()->cart->get_cart() as $cart_item) {
            $product_id = !empty($cart_item['variation_id']) && $cart_item['variation_id'] > 0
                ? (int) $cart_item['variation_id']
                : (int) ($cart_item['product_id'] ?? 0);

            if ($product_id <= 0 || !arraysubs_is_subscription_product($product_id)) {
                continue;
            }

            $subscription_data = arraysubs_get_product_subscription_data($product_id);
            if (is_array($subscription_data) && arraysubs_subscription_data_supports_renewal_sync($subscription_data)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check whether a selected gateway supports renewal sync.
     *
     * @param string $gateway_id Gateway ID.
     * @return bool
     */
    private function renewalSyncGatewayIsSupported(string $gateway_id): bool
    {
        if (!function_exists('arraysubs_is_renewal_sync_supported_gateway')) {
            return true;
        }

        $gateway = null;
        if (function_exists('WC') && WC()->payment_gateways()) {
            $gateways = WC()->payment_gateways()->payment_gateways();
            $gateway = $gateways[$gateway_id] ?? null;
        }

        return arraysubs_is_renewal_sync_supported_gateway($gateway_id, $gateway);
    }

    /**
     * Get the product ID from the current add-to-cart request.
     *
     * @return int
     */
    private function getRequestedProductId(): int
    {
        $variation_id = filter_input(INPUT_GET, 'variation_id', FILTER_VALIDATE_INT);

        if (!$variation_id) {
            $variation_id = filter_input(INPUT_POST, 'variation_id', FILTER_VALIDATE_INT);
        }

        if ($variation_id && $variation_id > 0) {
            return (int) $variation_id;
        }

        $product_id = filter_input(INPUT_GET, 'add-to-cart', FILTER_VALIDATE_INT);

        if (!$product_id) {
            $product_id = filter_input(INPUT_POST, 'add-to-cart', FILTER_VALIDATE_INT);
        }

        return $product_id && $product_id > 0 ? (int) $product_id : 0;
    }

    /**
     * Get the statuses considered live enough to block or migrate checkout.
     *
     * @return string[]
     */
    private function getRestrictedSubscriptionStatuses(): array
    {
        return ['arraysubs-active', 'arraysubs-on-hold', 'arraysubs-trial', 'arraysubs-pending'];
    }

    /**
     * Resolve the checkout identity used for duplicate checks and migration lookups.
     *
     * @param array $overrides Optional identity overrides.
     * @return array{customer_id:int,email:string}
     */
    private function getCheckoutIdentity(array $overrides = []): array
    {
        $customer_id = absint($overrides['customer_id'] ?? get_current_user_id());
        $email = sanitize_email($overrides['email'] ?? '');

        if (empty($email) && function_exists('WC') && WC()->customer) {
            $email = sanitize_email((string) WC()->customer->get_billing_email());
        }

        if ($customer_id <= 0 && !empty($email)) {
            $matched_user = get_user_by('email', $email);
            if ($matched_user instanceof \WP_User) {
                $customer_id = (int) $matched_user->ID;
            }
        }

        if (empty($email) && $customer_id > 0) {
            $user = get_userdata($customer_id);
            if ($user instanceof \WP_User) {
                $email = sanitize_email($user->user_email);
            }
        }

        return [
            'customer_id' => $customer_id,
            'email'       => $email,
        ];
    }

    /**
     * Build a subscription-only summary of the current cart.
     *
     * @param \WC_Cart|null $cart Cart object.
     * @return array<string,mixed>
     */
    private function getSubscriptionCartSummary($cart = null): array
    {
        $cart = $cart ?: (function_exists('WC') ? WC()->cart : null);

        $summary = [
            'subscription_item_count' => 0,
            'distinct_subscription_count' => 0,
            'first_subscription_product_id' => 0,
            'quantities' => [],
            'trial_item_count' => 0,
            'distinct_trial_count' => 0,
            'trial_quantities' => [],
        ];

        if (!$cart || !method_exists($cart, 'get_cart')) {
            return $summary;
        }

        $distinct_ids = [];
        $trial_distinct_ids = [];

        foreach ($cart->get_cart() as $cart_item) {
            $check_id = $this->getCartItemProductId($cart_item);
            if ($check_id <= 0 || !arraysubs_is_subscription_product($check_id)) {
                continue;
            }

            ++$summary['subscription_item_count'];
            if ($summary['first_subscription_product_id'] <= 0) {
                $summary['first_subscription_product_id'] = $check_id;
            }

            $distinct_ids[$check_id] = true;
            $summary['quantities'][$check_id] = ($summary['quantities'][$check_id] ?? 0) + max(1, absint($cart_item['quantity'] ?? 1));

            if (function_exists('arraysubs_product_has_free_trial') && arraysubs_product_has_free_trial($check_id)) {
                ++$summary['trial_item_count'];
                $trial_distinct_ids[$check_id] = true;
                $summary['trial_quantities'][$check_id] = ($summary['trial_quantities'][$check_id] ?? 0) + max(1, absint($cart_item['quantity'] ?? 1));
            }
        }

        $summary['distinct_subscription_count'] = count($distinct_ids);
        $summary['distinct_trial_count'] = count($trial_distinct_ids);

        return $summary;
    }

    /**
     * Check whether the requested cart state exceeds the single-trial limit.
     *
     * @param int         $check_id                Product or variation ID.
     * @param int         $quantity                Requested quantity.
     * @param string|null $excluded_cart_item_key  Optional cart item key to exclude.
     * @return bool
     */
    private function exceedsAllowedTrialCartQuantity(int $check_id, int $quantity, ?string $excluded_cart_item_key = null): bool
    {
        if (!function_exists('arraysubs_is_one_trial_per_customer') || !arraysubs_is_one_trial_per_customer()) {
            return false;
        }

        if (!function_exists('arraysubs_product_has_free_trial') || !arraysubs_product_has_free_trial($check_id)) {
            return false;
        }

        $total_trial_quantity = max(1, absint($quantity));

        if (!function_exists('WC') || !WC()->cart) {
            return $total_trial_quantity > 1;
        }

        foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
            if ($excluded_cart_item_key !== null && $cart_item_key === $excluded_cart_item_key) {
                continue;
            }

            $item_check_id = $this->getCartItemProductId($cart_item);

            if ($item_check_id <= 0 || !arraysubs_product_has_free_trial($item_check_id)) {
                continue;
            }

            $total_trial_quantity += max(1, absint($cart_item['quantity'] ?? 1));
        }

        return $total_trial_quantity > 1;
    }

    /**
     * Get the cart validation message for single-trial 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 effective subscription product or variation ID from a cart item.
     *
     * @param array $cart_item Cart item data.
     * @return int
     */
    private function getCartItemProductId(array $cart_item): int
    {
        $product_id = (int) ($cart_item['product_id'] ?? 0);
        $variation_id = (int) ($cart_item['variation_id'] ?? 0);

        return $variation_id > 0 ? $variation_id : $product_id;
    }
}
