<?php

/**
 * Subscription product helper functions
 *
 * @package ArraySubs\Functions
 */

defined('ABSPATH') || exit;

/**
 * Resolve a mixed product input to a WooCommerce product object.
 *
 * @param int|string|\WC_Product $product Product ID or object.
 * @return \WC_Product|null
 */
function arraysubs_get_wc_product($product): ?\WC_Product
{
    if ($product instanceof \WC_Product) {
        return $product;
    }

    if (is_numeric($product) && function_exists('wc_get_product')) {
        $product = wc_get_product($product);
    }

    return $product instanceof \WC_Product ? $product : null;
}

/**
 * Resolve the current single-product page product without trusting globals blindly.
 *
 * @return \WC_Product|null
 */
function arraysubs_get_current_product(): ?\WC_Product
{
    global $product;

    $current_product = arraysubs_get_wc_product($product);

    if ($current_product instanceof \WC_Product) {
        return $current_product;
    }

    if (!function_exists('is_product') || !is_product()) {
        return null;
    }

    $product_id = (int) get_queried_object_id();

    if ($product_id <= 0) {
        return null;
    }

    return arraysubs_get_wc_product($product_id);
}

/**
 * Check if a product is a subscription
 *
 * @param int|\WC_Product $product Product ID or object
 * @return bool True if subscription product
 */
function arraysubs_is_subscription_product($product): bool
{
    $product = arraysubs_get_wc_product($product);

    if (!$product instanceof \WC_Product) {
        return false;
    }

    $product_id = $product->get_id();
    $is_subscription = get_post_meta($product_id, '_is_subscription', true);

    return $is_subscription === 'yes';
}

/**
 * Get subscription product data
 *
 * @param int|\WC_Product $product Product ID or object
 * @return array|null Subscription data or null
 */
function arraysubs_get_product_subscription_data($product): ?array
{
    $product = arraysubs_get_wc_product($product);

    if (!$product instanceof \WC_Product || !arraysubs_is_subscription_product($product)) {
        return null;
    }

    $product_id = $product->get_id();

    // Use WooCommerce's get_price() which automatically returns:
    // - Sale price if currently on sale (respects sale schedule dates)
    // - Regular price otherwise
    $price = $product->get_price();

    $period = get_post_meta($product_id, '_subscription_period', true) ?: 'month';
    $interval = (int) get_post_meta($product_id, '_subscription_interval', true) ?: 1;
    $length = (int) get_post_meta($product_id, '_subscription_length', true) ?: 0;
    $has_different_renewal_price = get_post_meta($product_id, '_enable_renewal_price', true) === 'yes';

    if ($period === 'lifetime') {
        $interval = 1;
        $length = 0;
        $has_different_renewal_price = false;
    }

    return [
        'product_id'           => $product_id,
        'price'                => $price,
        'period'               => $period,
        'interval'             => $interval,
        'length'               => $length,
        'trial_length'         => (int) get_post_meta($product_id, '_trial_length', true) ?: 0,
        'trial_period'                  => get_post_meta($product_id, '_trial_period', true) ?: 'day',
        'signup_fee'                    => (float) get_post_meta($product_id, '_signup_fee', true) ?: 0,
        'enable_different_renewal_price' => $has_different_renewal_price,
        'different_renewal_price'       => get_post_meta($product_id, '_renewal_price', true),
        'different_renewal_price_after' => (int) get_post_meta($product_id, '_renewal_price_after', true) ?: 1,
    ];
}

/**
 * Check whether a subscription product includes a free trial.
 *
 * @param int|\WC_Product $product Product ID or object.
 * @return bool
 */
function arraysubs_product_has_free_trial($product): bool
{
    $data = arraysubs_get_product_subscription_data($product);

    return is_array($data)
        && !empty($data['trial_length'])
        && (int) $data['trial_length'] > 0;
}

/**
 * Get subscription price for display
 *
 * @param int|\WC_Product $product Product ID or object
 * @param bool            $include_schedule Include billing schedule
 * @return string Formatted price string
 */
function arraysubs_get_product_price_html($product, bool $include_schedule = true): string
{
    $product = arraysubs_get_wc_product($product);

    if (!$product instanceof \WC_Product || !arraysubs_is_subscription_product($product)) {
        return '';
    }

    $data = arraysubs_get_product_subscription_data($product);

    if (!$data) {
        return '';
    }

    $price_html = wc_price($data['price']);

    if ($include_schedule && ($data['period'] ?? '') !== 'lifetime') {
        $schedule = arraysubs_get_billing_price_suffix((int) $data['interval'], (string) $data['period']);
        $price_html .= ' / ' . esc_html($schedule);
    }

    return $price_html;
}

/**
 * Get the compact billing suffix used beside storefront prices.
 *
 * @param int    $interval Billing interval.
 * @param string $period   Billing period.
 * @return string
 */
function arraysubs_get_billing_price_suffix(int $interval, string $period): string
{
    $interval = max(1, $interval);

    $period_labels = [
        'day'   => _n('day', 'days', $interval, 'arraysubs'),
        'week'  => _n('week', 'weeks', $interval, 'arraysubs'),
        'month' => _n('month', 'months', $interval, 'arraysubs'),
        'year'  => _n('year', 'years', $interval, 'arraysubs'),
    ];

    $period_label = $period_labels[$period] ?? $period;

    if (1 === $interval) {
        return $period_label;
    }

    return sprintf(
        /* translators: 1: billing interval number, 2: billing period label. */
        __('%1$d %2$s', 'arraysubs'),
        $interval,
        $period_label
    );
}

/**
 * Get all subscription products
 *
 * @param array $args Query arguments
 * @return array Array of WC_Product objects
 */
function arraysubs_get_subscription_products(array $args = []): array
{
    $defaults = [
        'is_subscription' => true,
        'limit'           => -1,
        'status'          => 'publish',
        'return'          => 'objects',
    ];

    $args = wp_parse_args($args, $defaults);

    return wc_get_products($args);
}

/**
 * Get subscription term description for display
 *
 * @param int|\WC_Product $product Product ID or object
 * @return string Term description
 */
function arraysubs_get_product_term_description($product): string
{
    $product = arraysubs_get_wc_product($product);

    if (!$product instanceof \WC_Product || !arraysubs_is_subscription_product($product)) {
        return '';
    }

    $data = arraysubs_get_product_subscription_data($product);

    if (!$data) {
        return '';
    }

    if (($data['period'] ?? '') === 'lifetime') {
        return wc_price($data['price']);
    }

    $schedule = arraysubs_get_billing_schedule_string($data['interval'], $data['period']);
    $schedule_phrase = arraysubs_get_billing_schedule_phrase($data['interval'], $data['period']);

    // Build description based on pricing configuration
    if ($data['enable_different_renewal_price'] && !empty($data['different_renewal_price'])) {
        // Different renewal price after X payments
        if ($data['different_renewal_price_after'] > 1) {
            $description = sprintf(
                /* translators: %1$s: price, %2$s: billing schedule, %3$d: number of payments, %4$s: renewal price */
                __('%1$s %2$s for the first %3$d payments, then %4$s %2$s', 'arraysubs'),
                wc_price($data['price']),
                $schedule_phrase,
                $data['different_renewal_price_after'],
                wc_price($data['different_renewal_price'])
            );
        } else {
            /* translators: 1: initial payment amount, 2: renewal price amount, 3: billing cycle frequency */
            $description = sprintf(
                /* translators: 1: initial payment amount, 2: renewal price amount, 3: billing cycle frequency */
                __('First payment: %1$s, then %2$s %3$s', 'arraysubs'),
                wc_price($data['price']),
                wc_price($data['different_renewal_price']),
                $schedule_phrase
            );
        }
    } else {
        /* translators: 1: subscription price amount, 2: billing cycle frequency */
        $description = sprintf(
            /* translators: 1: subscription price amount, 2: billing cycle frequency */
            __('%1$s %2$s', 'arraysubs'),
            wc_price($data['price']),
            $schedule
        );
    }

    // Add signup fee if exists
    if ($data['signup_fee'] > 0) {
        /* translators: %s: one-time signup fee amount charged at purchase */
        $description .= ' ' . sprintf(
            /* translators: %s: one-time signup fee amount charged at purchase */
            __('+ %s signup fee', 'arraysubs'),
            wc_price($data['signup_fee'])
        );
    }

    // Add trial if exists
    if ($data['trial_length'] > 0) {
        $trial_schedule = arraysubs_get_duration_string($data['trial_length'], $data['trial_period']);
        /* translators: %s: trial period duration (e.g., "7 days", "1 month") */
        $description .= ' ' . sprintf(
            /* translators: %s: trial period duration (e.g., "7 days", "1 month") */
            __('(%s free trial)', 'arraysubs'),
            $trial_schedule
        );
    }

    // Add length if finite
    if ($data['length'] > 0) {
        /* translators: %d: total number of billing cycles for subscription duration */
        $length_text = sprintf(
            /* translators: %d: total number of billing cycles for subscription duration */
            _n('%d billing cycle', '%d billing cycles', $data['length'], 'arraysubs'),
            $data['length']
        );
        $description .= ' - ' . $length_text;
    }

    return $description;
}

/**
 * Calculate subscription end date
 *
 * @param string $start_date Start date (Y-m-d H:i:s)
 * @param int    $length     Subscription length (billing cycles)
 * @param int    $interval   Billing interval
 * @param string $period     Billing period (day|week|month|year)
 * @return string|null End date (Y-m-d H:i:s) or null if unlimited
 */
function arraysubs_calculate_subscription_end_date(string $start_date, int $length, int $interval, string $period): ?string
{
    if ($length <= 0) {
        return null; // Unlimited
    }

    $date = new \DateTime($start_date);
    $total_periods = $length * $interval;

    switch ($period) {
        case 'day':
            $date->modify("+{$total_periods} days");
            break;
        case 'week':
            $date->modify("+{$total_periods} weeks");
            break;
        case 'month':
            $date->modify("+{$total_periods} months");
            break;
        case 'year':
            $date->modify("+{$total_periods} years");
            break;
    }

    return $date->format('Y-m-d H:i:s');
}

/**
 * Check if product has variations with subscriptions
 *
 * @param int|\WC_Product $product Product ID or object
 * @return bool True if has subscription variations
 */
function arraysubs_has_subscription_variations($product): bool
{
    $product = arraysubs_get_wc_product($product);

    if (!$product instanceof \WC_Product || $product->get_type() !== 'variable') {
        return false;
    }

    $variations = $product->get_available_variations();

    foreach ($variations as $variation) {
        if (arraysubs_is_subscription_product($variation['variation_id'])) {
            return true;
        }
    }

    return false;
}
