<?php
/**
 * WooCommerce coupon management for ZERTI Financial › Coupons.
 */

if (!defined('ABSPATH')) {
    exit;
}

function zerti_wc_coupons_available(): bool
{
    return class_exists('WooCommerce') && class_exists('WC_Coupon');
}

function zerti_user_can_manage_wc_coupons(): bool
{
    return current_user_can('edit_shop_coupons') || current_user_can('manage_woocommerce');
}

/**
 * Localized label for a WooCommerce coupon discount type slug.
 */
function zerti_wc_coupon_type_label(string $slug): string
{
    $slug = sanitize_key($slug);
    if ($slug === '') {
        return '';
    }

    $labels = [
        'percent' => __('Percentage discount', 'zerti'),
        'fixed_cart' => __('Fixed cart discount', 'zerti'),
        'fixed_product' => __('Fixed product discount', 'zerti'),
    ];
    $label = isset($labels[$slug]) ? $labels[$slug] : '';

    if ($label !== '') {
        return $label;
    }

    /**
     * Filter coupon type label for custom discount types registered by other plugins.
     *
     * @param string $label Default empty string.
     * @param string $slug  Coupon discount type slug.
     */
    $filtered = (string) apply_filters('zerti_wc_coupon_type_label', '', $slug);

    return $filtered !== '' ? $filtered : $slug;
}

/**
 * @return array<string, string>
 */
function zerti_wc_coupon_type_choices(): array
{
    if (!function_exists('wc_get_coupon_types')) {
        return [];
    }

    $types = [];
    foreach (array_keys(wc_get_coupon_types()) as $slug) {
        $types[(string) $slug] = zerti_wc_coupon_type_label((string) $slug);
    }

    /** @var array<string, string> $types */
    return apply_filters('zerti_wc_coupon_type_choices', $types);
}

function zerti_wc_coupon_list_item(WC_Coupon $coupon): array
{
    $expiry = $coupon->get_date_expires();
    $usage_limit = $coupon->get_usage_limit();
    $product_ids = $coupon->get_product_ids();
    $usage_count = $coupon->get_usage_count();
    $discount_type = $coupon->get_discount_type();
    $amount_raw = (float) $coupon->get_amount();

    if ($discount_type === 'percent') {
        $decimals = function_exists('wc_get_price_decimals') ? wc_get_price_decimals() : 2;
        $amount_formatted = function_exists('wc_format_localized_decimal')
            ? wc_format_localized_decimal((string) $amount_raw, $decimals)
            : (string) $amount_raw;
        $amount_display = zerti_localize_digits($amount_formatted) . '%';
    } elseif (function_exists('zerti_format_admin_price_html')) {
        $amount_display = trim(wp_strip_all_tags(zerti_format_admin_price_html($amount_raw)));
    } else {
        $amount_display = zerti_localize_digits(wc_format_localized_price($amount_raw));
    }

    $expiry_ts = ($expiry && is_a($expiry, 'WC_DateTime')) ? (int) $expiry->getTimestamp() : 0;
    if ($expiry_ts > 0 && function_exists('zerti_format_date')) {
        $expiry_label = zerti_format_date($expiry);
    } elseif ($expiry_ts > 0) {
        $expiry_label = zerti_localize_digits(
            wp_date(get_option('date_format'), $expiry_ts, zerti_get_timezone())
        );
    } else {
        $expiry_label = '—';
    }

    $usage_limit_label = $usage_limit > 0 ? zerti_format_admin_number($usage_limit) : '∞';

    return [
        'id' => $coupon->get_id(),
        'code' => $coupon->get_code(),
        'type' => zerti_wc_coupon_type_label($coupon->get_discount_type()),
        'type_slug' => $coupon->get_discount_type(),
        'amount' => $amount_display,
        'amount_sort' => $amount_raw,
        'description' => $coupon->get_description(),
        'products' => $product_ids !== []
            ? zerti_localize_digits(implode(', ', array_map('strval', $product_ids)))
            : '—',
        'usage_count' => $usage_count,
        'usage_limit' => $usage_limit > 0 ? $usage_limit : null,
        'usage' => sprintf(
            /* translators: 1: usage count 2: usage limit or infinity symbol */
            __('%1$s / %2$s', 'zerti'),
            zerti_format_admin_number($usage_count),
            $usage_limit_label
        ),
        'expiry_date' => $expiry_label,
        'expiry_raw' => $expiry ? $expiry->date('Y-m-d') : '',
        'expiry_sort' => $expiry_ts,
    ];
}

/**
 * Map a localized coupon type label back to its WooCommerce slug.
 */
function zerti_wc_coupon_type_slug_from_label(string $label): string
{
    $label = trim($label);
    if ($label === '') {
        return '';
    }
    foreach (zerti_wc_coupon_type_choices() as $slug => $type_label) {
        if ((string) $type_label === $label) {
            return (string) $slug;
        }
    }

    return '';
}

/**
 * Normalize coupons grid dropdown filters (type column c1).
 *
 * @return array<string, string>
 */
function zerti_wc_coupons_grid_filters_from_json(string $filter_model_raw): array
{
    if ($filter_model_raw === '') {
        return [];
    }

    $filter_model = json_decode($filter_model_raw, true);
    if (!is_array($filter_model)) {
        return [];
    }

    $filters = [];
    if (isset($filter_model['c1']) && is_array($filter_model['c1'])) {
        $value = isset($filter_model['c1']['value']) ? sanitize_text_field((string) $filter_model['c1']['value']) : '';
        if ($value !== '') {
            $filters['type'] = $value;
        }
    }

    return $filters;
}

/**
 * @param array<string, mixed> $input
 * @return array{page:int,page_size:int,search:string,filter_model:string}
 */
function zerti_wc_coupons_grid_input_from_array(array $input): array
{
    return [
        'page' => isset($input['page']) ? (int) $input['page'] : 1,
        'page_size' => isset($input['page_size']) ? (int) $input['page_size'] : 50,
        'search' => isset($input['search']) ? sanitize_text_field(wp_unslash((string) $input['search'])) : '',
        'filter_model' => isset($input['filter_model']) ? wp_unslash((string) $input['filter_model']) : '',
    ];
}

/**
 * @param array<string, mixed> $input
 * @return array{rows:list<array<string, mixed>>, total:int}|WP_Error
 */
function zerti_fetch_wc_coupons_grid(array $input)
{
    if (!zerti_wc_coupons_available()) {
        return new WP_Error('wc_missing', 'woocommerce_required', ['status' => 400]);
    }

    $page = max(1, (int) ($input['page'] ?? 1));
    $page_size = max(1, min(100, (int) ($input['page_size'] ?? 50)));
    $search = isset($input['search']) ? sanitize_text_field((string) $input['search']) : '';
    $filter_model_raw = isset($input['filter_model']) ? (string) $input['filter_model'] : '';
    $grid_filters = zerti_wc_coupons_grid_filters_from_json($filter_model_raw);
    $type = '';
    if (!empty($grid_filters['type'])) {
        $type = zerti_wc_coupon_type_slug_from_label($grid_filters['type']);
    } elseif (isset($input['coupon_type'])) {
        $type = sanitize_key((string) $input['coupon_type']);
    }

    $query_args = [
        'post_type' => 'shop_coupon',
        'post_status' => 'publish',
        'posts_per_page' => $page_size,
        'paged' => $page,
        'orderby' => 'title',
        'order' => 'ASC',
        'fields' => 'ids',
    ];

    if ($search !== '') {
        $query_args['s'] = $search;
    }

    if ($type !== '' && array_key_exists($type, zerti_wc_coupon_type_choices())) {
        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Admin coupon list filter; paginated.
        $query_args['meta_query'] = [
            [
                'key' => 'discount_type',
                'value' => $type,
            ],
        ];
    }

    $q = new WP_Query($query_args);
    $rows = [];
    foreach ($q->posts as $post_id) {
        $coupon = new WC_Coupon((int) $post_id);
        if ($coupon->get_id() <= 0) {
            continue;
        }
        $rows[] = zerti_wc_coupon_list_item($coupon);
    }

    return [
        'rows' => $rows,
        'total' => (int) $q->found_posts,
    ];
}

function zerti_localize_wc_coupon_form_scripts(): void
{
    if (function_exists('zerti_maybe_reload_woocommerce_textdomain')) {
        zerti_maybe_reload_woocommerce_textdomain();
    }

    if (function_exists('zerti_wc_coupon_enhanced_select_params') && wp_script_is('wc-enhanced-select', 'registered')) {
        wp_localize_script('wc-enhanced-select', 'zerti_wc_enhanced_select_params', zerti_wc_coupon_enhanced_select_params());
    }

    if (wp_script_is('wc-admin-coupon-meta-boxes', 'registered')) {
        wp_localize_script(
            'wc-admin-coupon-meta-boxes',
            'zerti_woocommerce_admin_meta_boxes_coupon',
            [
                'generate_button_text' => esc_html__('Generate coupon code', 'zerti'),
                'characters' => apply_filters('woocommerce_coupon_code_generator_characters', 'ABCDEFGHJKMNPQRSTUVWXYZ23456789'),
                'char_length' => apply_filters('woocommerce_coupon_code_generator_character_length', 8),
                'prefix' => apply_filters('woocommerce_coupon_code_generator_prefix', ''),
                'suffix' => apply_filters('woocommerce_coupon_code_generator_suffix', ''),
            ]
        );
    }
}

function zerti_enqueue_wc_coupon_form_assets(): void
{
    if (!function_exists('WC')) {
        return;
    }

    wp_enqueue_style('zerti-woocommerce-admin');
    wp_enqueue_style('zerti-wc-select2');
    wp_enqueue_script('wc-enhanced-select');
    wp_enqueue_script('wc-admin-meta-boxes');
    wp_enqueue_script('wc-admin-coupon-meta-boxes');

    zerti_localize_wc_coupon_form_scripts();
}

/**
 * Format coupon expiry for the active admin calendar input (same as product sale dates).
 */
function zerti_wc_coupon_format_expiry_display(int $coupon_id): string
{
    if ($coupon_id <= 0) {
        return '';
    }

    $coupon = new WC_Coupon($coupon_id);

    return function_exists('zerti_product_edit_format_sale_date')
        ? zerti_product_edit_format_sale_date($coupon->get_date_expires('edit'))
        : '';
}

/**
 * Parse coupon expiry from admin UI into WooCommerce Y-m-d storage.
 */
function zerti_wc_coupon_parse_expiry_for_storage(string $raw): string
{
    $raw = trim($raw);
    if ($raw === '') {
        return '';
    }

    if (!function_exists('zerti_parse_admin_date_string')) {
        return wc_clean($raw);
    }

    $ts = zerti_parse_admin_date_string($raw);
    if ($ts === null) {
        return '';
    }

    return (new DateTimeImmutable('@' . $ts))
        ->setTimezone(zerti_get_timezone())
        ->format('Y-m-d');
}

/**
 * Replace WC jQuery UI expiry input with ZERTI admin datepicker markup.
 */
function zerti_wc_coupon_patch_expiry_field_html(string $html, int $coupon_id): string
{
    if (!preg_match('/<input\b[^>]*\bid=(["\'])expiry_date\1[^>]*>/i', $html, $match)) {
        return $html;
    }

    $display = zerti_wc_coupon_format_expiry_display($coupon_id);
    $type = function_exists('zerti_admin_date_input_type') ? zerti_admin_date_input_type() : 'text';
    $data_attr = function_exists('zerti_admin_date_input_data_attr') ? zerti_admin_date_input_data_attr() : 'data-zerti-jalali-date';
    $placeholder = function_exists('zerti_admin_date_placeholder') ? zerti_admin_date_placeholder() : '';
    $dir = $type === 'date'
        ? 'ltr'
        : (function_exists('zerti_is_gregorian_calendar') && zerti_is_gregorian_calendar() ? 'ltr' : 'rtl');

    $replacement = sprintf(
        '<input type="%s" class="form-control zerti-admin-date-input" id="expiry_date" name="expiry_date" %s dir="%s" value="%s"%s>',
        esc_attr($type),
        $data_attr,
        esc_attr($dir),
        esc_attr($display),
        $type === 'text'
            ? ' inputmode="numeric" autocomplete="off" placeholder="' . esc_attr($placeholder) . '"'
            : ''
    );

    return str_replace($match[0], $replacement, $html);
}

/**
 * Load WooCommerce admin meta-box helpers (needed on admin-ajax coupon editor).
 */
function zerti_wc_coupon_ensure_admin_dependencies(): void
{
    if (!function_exists('woocommerce_wp_select')) {
        $functions = WC()->plugin_path() . '/includes/admin/wc-meta-box-functions.php';
        if (is_readable($functions)) {
            require_once $functions;
        }
    }

    if (!class_exists('WC_Meta_Box_Coupon_Data', false)) {
        include_once WC()->plugin_path() . '/includes/admin/meta-boxes/class-wc-meta-box-coupon-data.php';
    }
}

/**
 * Render coupon editor form (WC meta fields inside ZERTI shell).
 */
function zerti_render_wc_coupon_editor(int $coupon_id): void
{
    if (!zerti_wc_coupons_available()) {
        return;
    }

    $locale_switched = false;
    $target_locale = function_exists('zerti_get_effective_locale') ? zerti_get_effective_locale() : '';
    if ($target_locale !== '' && function_exists('switch_to_locale') && $target_locale !== get_locale()) {
        $locale_switched = switch_to_locale($target_locale);
        if ($locale_switched) {
            zerti_load_plugin_textdomain();
            zerti_maybe_reload_woocommerce_textdomain();
        }
    }
    $restore_coupon_editor_locale = static function () use ($locale_switched): void {
        if ($locale_switched && function_exists('restore_previous_locale')) {
            restore_previous_locale();
        }
    };

    if ($coupon_id > 0) {
        $post = get_post($coupon_id);
        if (!$post instanceof WP_Post || $post->post_type !== 'shop_coupon') {
            echo '<p class="alert alert-warning mb-0">' . esc_html__('Coupon not found.', 'zerti') . '</p>';
            $restore_coupon_editor_locale();

            return;
        }
        if (!current_user_can('edit_post', $coupon_id)) {
            echo '<p class="alert alert-warning mb-0">' . esc_html__('You do not have permission to edit this coupon.', 'zerti') . '</p>';
            $restore_coupon_editor_locale();

            return;
        }
    } else {
        $post = get_default_post_to_edit('shop_coupon', false);
        if (!$post instanceof WP_Post) {
            echo '<p class="alert alert-warning mb-0">' . esc_html__('Could not prepare a new coupon.', 'zerti') . '</p>';
            $restore_coupon_editor_locale();

            return;
        }
    }

    // Assets are enqueued on admin_enqueue_scripts via the financial-coupons bundle.
    zerti_wc_coupon_ensure_admin_dependencies();

    $is_new = $coupon_id <= 0;
    ?>
    <form class="zerti-coupon-form post-type-shop_coupon" data-zerti-coupon-form="1" novalidate>
        <input type="hidden" name="coupon_id" value="<?php echo esc_attr((string) $coupon_id); ?>">
        <div class="alert alert-danger py-2 small d-none zerti-coupon-form-error" role="alert"></div>
        <div class="alert alert-success py-2 small d-none zerti-coupon-form-success" role="status"></div>

        <div class="zerti-coupon-form-basics row g-2 mb-0">
            <div class="col-12 col-md-6">
                <label class="form-label" for="title"><?php esc_html_e('Coupon code', 'zerti'); ?> <?php if ($is_new) : ?><span class="text-danger">*</span><?php endif; ?></label>
                <div class="zerti-coupon-code-row">
                    <input
                        type="text"
                        class="form-control"
                        id="title"
                        name="post_title"
                        value="<?php echo esc_attr($post->post_title); ?>"
                        <?php echo $is_new ? 'required' : 'readonly'; ?>
                        dir="ltr"
                        autocomplete="off"
                    >
                    <?php if ($is_new) : ?>
                        <button type="button" class="btn btn-sm btn-outline-secondary zerti-coupon-generate-code" data-zerti-coupon-generate>
                            <?php esc_html_e('Generate coupon code', 'zerti'); ?>
                        </button>
                    <?php endif; ?>
                </div>
            </div>
            <div class="col-12 col-md-6">
                <label class="form-label" for="coupon_description"><?php esc_html_e('Description', 'zerti'); ?></label>
                <input
                    type="text"
                    class="form-control"
                    id="coupon_description"
                    name="excerpt"
                    value="<?php echo esc_attr($post->post_excerpt); ?>"
                >
            </div>
        </div>

        <div class="zerti-coupon-wc-meta">
            <?php
            ob_start();
            WC_Meta_Box_Coupon_Data::output($post);
            // Trusted WooCommerce meta-box markup for authorized shop managers; wp_kses_post strips inputs/selects.
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            echo zerti_wc_coupon_patch_expiry_field_html((string) ob_get_clean(), $coupon_id);
            ?>
        </div>
    </form>
    <?php

    $restore_coupon_editor_locale();
}

/**
 * @param array<string, mixed> $payload
 * @return array{id:int, code:string}|WP_Error
 */
function zerti_wc_coupon_save_from_payload(array $payload)
{
    if (!zerti_wc_coupons_available() || !zerti_user_can_manage_wc_coupons()) {
        return new WP_Error('forbidden', 'forbidden', ['status' => 403]);
    }

    $coupon_id = absint($payload['coupon_id'] ?? 0);
    $code = isset($payload['post_title']) ? wc_format_coupon_code(sanitize_text_field((string) $payload['post_title'])) : '';
    $excerpt = isset($payload['excerpt']) ? sanitize_textarea_field((string) $payload['excerpt']) : '';

    if ($coupon_id <= 0) {
        if ($code === '') {
            return new WP_Error('missing_code', __('Coupon code is required.', 'zerti'), ['status' => 400]);
        }
        $coupon_id = wp_insert_post(
            [
                'post_type' => 'shop_coupon',
                'post_title' => $code,
                'post_excerpt' => $excerpt,
                'post_status' => 'publish',
            ],
            true
        );
        if (is_wp_error($coupon_id)) {
            return $coupon_id;
        }
    } else {
        if (!current_user_can('edit_post', $coupon_id)) {
            return new WP_Error('forbidden', 'forbidden', ['status' => 403]);
        }
        $existing = get_post($coupon_id);
        if (!$existing instanceof WP_Post || $existing->post_type !== 'shop_coupon') {
            return new WP_Error('not_found', __('Coupon not found.', 'zerti'), ['status' => 404]);
        }
        $code = $existing->post_title;
        wp_update_post(
            [
                'ID' => $coupon_id,
                'post_excerpt' => $excerpt,
            ]
        );
    }

    $product_categories = isset($payload['product_categories']) ? array_map('absint', (array) $payload['product_categories']) : [];
    $exclude_product_categories = isset($payload['exclude_product_categories']) ? array_map('absint', (array) $payload['exclude_product_categories']) : [];

    $coupon = new WC_Coupon($coupon_id);
    $result = $coupon->set_props(
        [
            'code' => $code,
            'discount_type' => isset($payload['discount_type']) ? wc_clean((string) $payload['discount_type']) : $coupon->get_discount_type('edit'),
            'amount' => isset($payload['coupon_amount']) ? wc_format_decimal((string) $payload['coupon_amount']) : $coupon->get_amount('edit'),
            'date_expires' => isset($payload['expiry_date'])
                ? zerti_wc_coupon_parse_expiry_for_storage((string) $payload['expiry_date'])
                : null,
            'individual_use' => !empty($payload['individual_use']),
            'product_ids' => isset($payload['product_ids']) ? array_filter(array_map('absint', (array) $payload['product_ids'])) : [],
            'excluded_product_ids' => isset($payload['exclude_product_ids']) ? array_filter(array_map('absint', (array) $payload['exclude_product_ids'])) : [],
            'usage_limit' => isset($payload['usage_limit']) ? absint($payload['usage_limit']) : 0,
            'usage_limit_per_user' => isset($payload['usage_limit_per_user']) ? absint($payload['usage_limit_per_user']) : 0,
            'limit_usage_to_x_items' => isset($payload['limit_usage_to_x_items']) ? absint($payload['limit_usage_to_x_items']) : 0,
            'free_shipping' => !empty($payload['free_shipping']),
            'product_categories' => array_filter($product_categories),
            'excluded_product_categories' => array_filter($exclude_product_categories),
            'exclude_sale_items' => !empty($payload['exclude_sale_items']),
            'minimum_amount' => isset($payload['minimum_amount']) ? wc_format_decimal((string) $payload['minimum_amount']) : '',
            'maximum_amount' => isset($payload['maximum_amount']) ? wc_format_decimal((string) $payload['maximum_amount']) : '',
            'email_restrictions' => isset($payload['customer_email'])
                ? array_filter(array_map('trim', explode(',', wc_clean((string) $payload['customer_email']))))
                : [],
        ]
    );

    if (is_wp_error($result)) {
        return $result;
    }

    $coupon->save();
    do_action('woocommerce_coupon_options_save', $coupon_id, $coupon);

    return [
        'id' => $coupon_id,
        'code' => $coupon->get_code(),
    ];
}

/**
 * @return true|WP_Error
 */
function zerti_wc_coupon_delete(int $coupon_id)
{
    if (!zerti_wc_coupons_available() || !zerti_user_can_manage_wc_coupons()) {
        return new WP_Error('forbidden', 'forbidden', ['status' => 403]);
    }
    if ($coupon_id <= 0 || !current_user_can('delete_post', $coupon_id)) {
        return new WP_Error('forbidden', 'forbidden', ['status' => 403]);
    }
    $post = get_post($coupon_id);
    if (!$post instanceof WP_Post || $post->post_type !== 'shop_coupon') {
        return new WP_Error('not_found', __('Coupon not found.', 'zerti'), ['status' => 404]);
    }

    $deleted = wp_trash_post($coupon_id);
    if (!$deleted) {
        return new WP_Error('delete_failed', __('Could not delete coupon.', 'zerti'), ['status' => 500]);
    }

    return true;
}
