<?php
if (!defined('ABSPATH')) exit;
if (!defined('STAKMV_AUCTION_BIDS_TABLE')) {
    return;
}
function stakmv_auction_payment_timeout_hours($auction_id = 0) {
    return (int) apply_filters(
        'stakmv_auction_payment_timeout_hours',
        get_option('stakmv_auction_payment_timeout', 48),
        $auction_id
    );
}

function stakmv_auction_failure_action($auction_id = 0) {
    return apply_filters(
        'stakmv_auction_failure_action',
        stakmv_get_option('auction_failure_action', 'next_bidder'),
        $auction_id
    );
}

/**
 * Get a plugin option by canonical stakmv_* key.
 *
 * @param string $suffix  Option suffix without prefix.
 * @param mixed  $default Default value.
 * @return mixed
 */
function stakmv_get_option($suffix, $default = false) {
    $suffix = sanitize_key((string) $suffix);
    if ($suffix === '') {
        return $default;
    }

    return get_option('stakmv_' . $suffix, $default);
}

/**
 * Update a plugin option by canonical stakmv_* key.
 *
 * @param string $suffix Option suffix without prefix.
 * @param mixed  $value  Option value.
 * @return bool
 */
function stakmv_update_option($suffix, $value) {
    $suffix = sanitize_key((string) $suffix);
    if ($suffix === '') {
        return false;
    }

    return update_option('stakmv_' . $suffix, $value);
}

/**
 * Get a plugin transient by canonical stakmv_* key.
 *
 * @param string $suffix Transient suffix without prefix.
 * @return mixed
 */
function stakmv_get_transient($suffix) {
    $suffix = sanitize_key((string) $suffix);
    if ($suffix === '') {
        return false;
    }

    return get_transient('stakmv_' . $suffix);
}

/**
 * Set a plugin transient by canonical stakmv_* key.
 *
 * @param string $suffix     Transient suffix without prefix.
 * @param mixed  $value      Value.
 * @param int    $expiration Expiration in seconds.
 * @return bool
 */
function stakmv_set_transient($suffix, $value, $expiration = 0) {
    $suffix = sanitize_key((string) $suffix);
    if ($suffix === '') {
        return false;
    }

    return set_transient('stakmv_' . $suffix, $value, (int) $expiration);
}

/**
 * Delete a plugin transient by canonical stakmv_* key.
 *
 * @param string $suffix Transient suffix without prefix.
 * @return bool
 */
function stakmv_delete_transient($suffix) {
    $suffix = sanitize_key((string) $suffix);
    if ($suffix === '') {
        return false;
    }

    return delete_transient('stakmv_' . $suffix);
}

/**
 * Get the public vendor display name stored by this plugin.
 *
 * WordPress.org does not permit this plugin to update core user profile fields,
 * so editable vendor profile values are stored in plugin-owned user meta.
 */
function stakmv_get_vendor_display_name($user_id) {
    $user_id = (int) $user_id;
    if ($user_id <= 0) {
        return '';
    }

    $display_name = sanitize_text_field((string) get_user_meta($user_id, 'stakmv_display_name', true));
    if ($display_name !== '') {
        return $display_name;
    }

    $user = get_userdata($user_id);
    return $user ? (string) $user->display_name : '';
}

/**
 * Get the public vendor bio stored by this plugin.
 */
function stakmv_get_vendor_bio($user_id) {
    $user_id = (int) $user_id;
    if ($user_id <= 0) {
        return '';
    }

    $bio = sanitize_textarea_field((string) get_user_meta($user_id, 'stakmv_bio', true));
    if ($bio !== '') {
        return $bio;
    }

    return sanitize_textarea_field((string) get_user_meta($user_id, 'description', true));
}

/**
 * Get the public vendor website stored by this plugin.
 */
function stakmv_get_vendor_website($user_id) {
    $user_id = (int) $user_id;
    if ($user_id <= 0) {
        return '';
    }

    $website = esc_url_raw((string) get_user_meta($user_id, 'stakmv_website', true));
    if ($website !== '') {
        return $website;
    }

    $user = get_userdata($user_id);
    return $user ? esc_url_raw((string) $user->user_url) : '';
}

/**
 * Global switch for auction mechanics.
 */
function stakmv_auctions_enabled() {
    return stakmv_get_option('enable_auctions', 'yes') === 'yes';
}

/**
 * Relist duration (days) for admin/vendor relist actions.
 */
function stakmv_get_relist_duration_days() {
    $days = (int) apply_filters('stakmv_relist_duration_days', 7);
    return max(1, $days);
}

/**
 * Resolve listing shipping mode from saved listing metadata.
 *
 * Modes:
 * - calculated: live/estimated rates at checkout
 * - flat: fixed seller-set shipping cost
 * - free: seller covers shipping cost
 * - pickup_only: local pickup only
 */
function stakmv_get_listing_shipping_mode($listing_id) {
    $listing_id = (int) $listing_id;
    if ($listing_id <= 0) {
        return 'calculated';
    }

    $mode = sanitize_key((string) get_post_meta($listing_id, '_stakmv_auction_shipping_mode', true));
    if (in_array($mode, array('calculated', 'flat', 'free', 'pickup_only'), true)) {
        return $mode;
    }

    $carrier_raw = strtolower(trim((string) get_post_meta($listing_id, '_stakmv_auction_shipping_carrier', true)));
    if (in_array($carrier_raw, array('free shipping', 'free'), true)) {
        return 'free';
    }
    if (in_array($carrier_raw, array('pickup only', 'pickup', 'local pickup'), true)) {
        return 'pickup_only';
    }

    $flat_cost = (float) get_post_meta($listing_id, '_stakmv_auction_shipping_cost', true);
    if ($flat_cost > 0) {
        return 'flat';
    }

    return 'calculated';
}

/**
 * Shipping scope per listing.
 *
 * Values:
 * - international: ships worldwide
 * - domestic: ships only within vendor origin country
 * - selected: ships only to explicitly selected countries
 */
function stakmv_get_listing_shipping_scope($listing_id) {
    $listing_id = (int) $listing_id;
    if ($listing_id <= 0) {
        return 'international';
    }

    $scope = sanitize_key((string) get_post_meta($listing_id, '_stakmv_auction_shipping_scope', true));
    if (!in_array($scope, array('international', 'domestic', 'selected'), true)) {
        return 'international';
    }

    return $scope;
}

/**
 * Check whether a listing can ship to the destination country.
 *
 * @param int    $listing_id
 * @param string $destination_country ISO-2 country code.
 * @return bool
 */
function stakmv_listing_ships_to_country($listing_id, $destination_country) {
    $listing_id = (int) $listing_id;
    $country = strtoupper(trim((string) $destination_country));
    if ($listing_id <= 0 || $country === '') {
        return true;
    }

    $scope = stakmv_get_listing_shipping_scope($listing_id);
    if ($scope === 'international') {
        return true;
    }

    if ($scope === 'selected') {
        $allowed = get_post_meta($listing_id, '_stakmv_auction_shipping_countries', true);
        if (!is_array($allowed)) {
            $allowed = array();
        }
        $allowed = array_values(array_filter(array_map(function ($code) {
            return strtoupper(sanitize_text_field((string) $code));
        }, $allowed)));

        return in_array($country, $allowed, true);
    }

    $vendor_id = (int) get_post_field('post_author', $listing_id);
    $origin_country = strtoupper(trim((string) get_user_meta($vendor_id, 'stakmv_ship_origin_country', true)));
    if ($origin_country === '' && function_exists('wc_get_base_location')) {
        $base = wc_get_base_location();
        if (is_array($base) && !empty($base['country'])) {
            $origin_country = strtoupper(sanitize_text_field((string) $base['country']));
        }
    }

    if ($origin_country === '') {
        return true;
    }

    return $origin_country === $country;
}

/**
 * Core condition options.
 *
 * @return array<string,array{label:string,detail:string}>
 */
function stakmv_get_default_condition_options() {
    return array(
        'new' => array(
            'label'  => 'New',
            'detail' => 'Factory sealed, never used',
        ),
        'like-new' => array(
            'label'  => 'Like New',
            'detail' => 'Opened or displayed, no wear',
        ),
        'used-good' => array(
            'label'  => 'Used - Good',
            'detail' => 'Normal wear, fully functional',
        ),
        'used-fair' => array(
            'label'  => 'Used - Fair',
            'detail' => 'Noticeable wear or flaws (still works)',
        ),
    );
}

/**
 * Filterable condition options.
 *
 * @return array<string,array{label:string,detail:string}>
 */
function stakmv_get_condition_options() {
    $options = stakmv_get_default_condition_options();
    $options = apply_filters('stakmv_condition_options', $options);

    if (!is_array($options) || empty($options)) {
        $options = stakmv_get_default_condition_options();
    }

    $normalized = array();
    foreach ($options as $key => $row) {
        $slug = sanitize_title((string) $key);
        if ($slug === '' || !is_array($row)) {
            continue;
        }
        $label = isset($row['label']) ? sanitize_text_field((string) $row['label']) : '';
        $detail = isset($row['detail']) ? sanitize_text_field((string) $row['detail']) : '';
        if ($label === '') {
            continue;
        }
        $normalized[$slug] = array(
            'label'  => $label,
            'detail' => $detail,
        );
    }

    return !empty($normalized) ? $normalized : stakmv_get_default_condition_options();
}

/**
 * Create/edit listing form settings defaults.
 *
 * @return array{sections:array<string,string>,fields:array<string,string>}
 */
function stakmv_get_listing_form_defaults() {
    return array(
        'sections' => array(
            'item_details'      => 'yes',
            'category_filters'  => 'yes',
            'pricing_auction'   => 'yes',
            'location_shipping' => 'yes',
            'faq'               => 'yes',
            'photos'            => 'yes',
        ),
        'fields' => array(
            'title'                    => 'yes',
            'description'              => 'yes',
            'condition'                => 'yes',
            'quantity'                 => 'yes',
            'category'                 => 'yes',
            'attributes'               => 'yes',
            'listing_type'             => 'yes',
            'start_price'              => 'yes',
            'buy_now_price'            => 'yes',
            'end_date'                 => 'yes',
            'location'                 => 'yes',
            'shipping_mode'            => 'yes',
            'shipping_scope'           => 'yes',
            'handling_time'            => 'yes',
            'returns_policy'           => 'yes',
            'flat_shipping_cost'       => 'yes',
            'package_metrics'          => 'yes',
            'supported_carriers'       => 'yes',
            'faq_builder'              => 'yes',
            'photo_upload'             => 'yes',
            'delete_listing_action'    => 'yes',
        ),
    );
}

/**
 * Core form controls that cannot be disabled.
 *
 * @return array{sections:string[],fields:string[]}
 */
function stakmv_get_listing_form_locked_controls() {
    return array(
        'sections' => array(
            'pricing_auction',
            'location_shipping',
        ),
        'fields' => array(
            'title',
            'listing_type',
            'start_price',
            'buy_now_price',
            'end_date',
            'shipping_mode',
        ),
    );
}

/**
 * Normalized listing form settings with defaults and lock enforcement.
 *
 * @return array{sections:array<string,string>,fields:array<string,string>}
 */
function stakmv_get_listing_form_settings() {
    $defaults = stakmv_get_listing_form_defaults();
    $saved = stakmv_get_option('listing_form_settings', array());
    $locked = stakmv_get_listing_form_locked_controls();

    $settings = array(
        'sections' => $defaults['sections'],
        'fields'   => $defaults['fields'],
    );

    if (is_array($saved)) {
        foreach (array('sections', 'fields') as $group) {
            if (empty($saved[$group]) || !is_array($saved[$group])) {
                continue;
            }
            foreach ($defaults[$group] as $key => $_default_state) {
                if (!array_key_exists($key, $saved[$group])) {
                    continue;
                }
                $settings[$group][$key] = ((string) $saved[$group][$key] === 'no') ? 'no' : 'yes';
            }
        }
    }

    foreach (array('sections', 'fields') as $group) {
        if (empty($locked[$group]) || !is_array($locked[$group])) {
            continue;
        }
        foreach ($locked[$group] as $key) {
            if (isset($settings[$group][$key])) {
                $settings[$group][$key] = 'yes';
            }
        }
    }

    return $settings;
}

/**
 * Whether a create/edit listing section is enabled.
 *
 * @param string $section_key
 * @return bool
 */
function stakmv_is_listing_form_section_enabled($section_key) {
    $section_key = sanitize_key((string) $section_key);
    if ($section_key === '') {
        return true;
    }
    $settings = stakmv_get_listing_form_settings();
    if (!isset($settings['sections'][$section_key])) {
        return true;
    }
    return $settings['sections'][$section_key] !== 'no';
}

/**
 * Whether a create/edit listing field is enabled.
 *
 * @param string $field_key
 * @return bool
 */
function stakmv_is_listing_form_field_enabled($field_key) {
    $field_key = sanitize_key((string) $field_key);
    if ($field_key === '') {
        return true;
    }
    $settings = stakmv_get_listing_form_settings();
    if (!isset($settings['fields'][$field_key])) {
        return true;
    }
    return $settings['fields'][$field_key] !== 'no';
}

function stakmv_get_highest_bid($auction_id) {
    global $wpdb;
    $bids_table = $wpdb->prefix . 'stakmv_auction_bids';

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is plugin-controlled and escaped; query is a bounded aggregate by auction id.
    $highest = $wpdb->get_var(
        $wpdb->prepare(
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Dynamic table name uses current site prefix.
            "SELECT MAX(bid_amount) FROM {$bids_table} WHERE auction_id = %d",
            (int) $auction_id
        )
    );

    if ($highest !== null) {
        return (float) $highest;
    }

    return (float) get_post_meta($auction_id, '_stakmv_auction_start_price', true);
}

function stakmv_get_bid_leader( $auction_id ) {
    global $wpdb;
    $bids_table = $wpdb->prefix . 'stakmv_auction_bids';

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name is plugin-controlled and escaped; query is bounded.
    $row = $wpdb->get_row(
        $wpdb->prepare(
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Dynamic table name uses current site prefix.
            "SELECT user_id, bid_amount FROM {$bids_table} WHERE auction_id = %d ORDER BY bid_amount DESC, created_at ASC, id ASC LIMIT 1",
            (int) $auction_id
        ),
        ARRAY_A
    );

    if ( ! is_array( $row ) ) {
        return array(
            'user_id'    => 0,
            'bid_amount' => 0.0,
        );
    }

    return array(
        'user_id'    => isset( $row['user_id'] ) ? (int) $row['user_id'] : 0,
        'bid_amount' => isset( $row['bid_amount'] ) ? (float) $row['bid_amount'] : 0.0,
    );
}

function stakmv_sync_auction_bid_meta( $auction_id ) {
    $auction_id = (int) $auction_id;
    if ( $auction_id <= 0 ) {
        return;
    }

    $highest_bid = (float) stakmv_get_highest_bid( $auction_id );
    $bid_count   = function_exists( 'stakmv_get_bid_count' ) ? (int) stakmv_get_bid_count( $auction_id ) : 0;
    $leader      = stakmv_get_bid_leader( $auction_id );

    update_post_meta( $auction_id, '_stakmv_auction_current_bid', $highest_bid );
    update_post_meta( $auction_id, '_stakmv_auction_bid_count', $bid_count );

    if ( ! empty( $leader['user_id'] ) ) {
        update_post_meta( $auction_id, '_stakmv_auction_highest_bidder', (int) $leader['user_id'] );
    } else {
        delete_post_meta( $auction_id, '_stakmv_auction_highest_bidder' );
    }
}

function stakmv_insert_bid_row( $auction_id, $user_id, $bid_amount ) {
    global $wpdb;

    $auction_id = (int) $auction_id;
    $user_id    = (int) $user_id;
    $bid_amount = (float) $bid_amount;

    if ( $auction_id <= 0 || $user_id <= 0 || $bid_amount <= 0 ) {
        return 0;
    }

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Intentional insert for bid persistence.
    $inserted = $wpdb->insert(
        STAKMV_AUCTION_BIDS_TABLE,
        array(
            'auction_id' => $auction_id,
            'user_id'    => $user_id,
            'bid_amount' => $bid_amount,
        ),
        array( '%d', '%d', '%f' )
    );

    if ( false === $inserted ) {
        return 0;
    }

    stakmv_sync_auction_bid_meta( $auction_id );

    return (int) $wpdb->insert_id;
}

function stakmv_add_user_notification( $user_id, $message ) {
    $user_id = (int) $user_id;
    $message = trim( (string) $message );

    if ( $user_id <= 0 || '' === $message ) {
        return;
    }

    $notes = get_user_meta( $user_id, 'stakmv_notifications', true );
    $notes = is_array( $notes ) ? $notes : array();

    array_unshift( $notes, $message );
    if ( count( $notes ) > 100 ) {
        $notes = array_slice( $notes, 0, 100 );
    }

    update_user_meta( $user_id, 'stakmv_notifications', $notes );
}

function stakmv_get_vendor_auctions($vendor_id) {
    return wc_get_products([
        'author' => $vendor_id,
        'type'   => 'auction',
        'limit'  => -1,
    ]);
}

function stakmv_count_vendor_auctions($vendor_id, $status) {
    // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key,WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Query is constrained by author/type and used for vendor dashboard counters.
    $products = wc_get_products([
        'author' => $vendor_id,
        'type'   => 'auction',
        'meta_key'   => '_stakmv_auction_status',
        'meta_value' => $status,
        'limit'      => -1,
    ]);
    // phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_key,WordPress.DB.SlowDBQuery.slow_db_query_meta_value

    return count($products);
}

/**
 * -----------------------------
 * Filterable data-provider wrappers
 * -----------------------------
 *
 * These lightweight wrappers return sensible defaults and allow
 * extensions to supply real data via filters.
 */

/**
 * Get vendor stats (listings, bids, sales, balance)
 * Default values are conservative; extensions may replace via filter.
 */
function stakmv_get_vendor_stats($vendor_id) {
    $defaults = [
        'listings' => stakmv_count_vendor_auctions($vendor_id, 'active'),
        'bids'     => 0,
        'sales'    => 0,
        'balance'  => 0,
    ];

    return apply_filters('stakmv_vendor_stats', $defaults, $vendor_id);
}

/**
 * Get vendor bids
 * Returns an empty array by default; extensions can provide real bid records.
 */
function stakmv_get_vendor_bids($vendor_id) {
    $default = [];
    return apply_filters('stakmv_get_vendor_bids', $default, $vendor_id);
}

/**
 * Get wallet balance (default 0.0)
 * Extensions can hook 'stakmv_get_wallet_balance' to return ledger-based balance.
 */
function stakmv_get_wallet_balance($vendor_id) {
    $default = 0.0;
    return apply_filters('stakmv_get_wallet_balance', $default, $vendor_id);
}

/**
 * Calculate expected delivery days for an order based on shipping country vs store country.
 * Simple heuristic:
 *  - Same country: 3 days
 *  - Different country: 7 days
 */
function stakmv_calculate_expected_delivery_days_for_order( $order_id ) {
    $order = wc_get_order( $order_id );
    if ( ! $order ) {
        return 0;
    }

    $ship_country = $order->get_shipping_country();
    if ( empty( $ship_country ) ) {
        $ship_country = $order->get_billing_country();
    }

    $store_default = get_option( 'woocommerce_default_country', '' ); // e.g. "US:CA"
    $parts = explode( ':', $store_default );
    $store_country = strtoupper( $parts[0] ?? '' );

    if ( empty( $ship_country ) || empty( $store_country ) ) {
        return 0;
    }

    return strtoupper( $ship_country ) === $store_country ? 3 : 7;
}

if ( ! function_exists( 'stakmv_get_chart_data' ) ) {
    /**
     * Return chart payload for vendor dashboard analytics.
     *
     * @param int $user_id User ID.
     * @return array
     */
    function stakmv_get_chart_data( $user_id ) {
        $user_id = (int) $user_id;
        if ( $user_id <= 0 ) {
            return array( 'earnings' => array(), 'bids' => array(), 'watchers' => array( 1, 2, 3, 4, 6, 8, 12 ) );
        }

        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Dashboard chart query; read-only and bounded.
        $earnings = $wpdb->get_results(
            "SELECT DATE(post_date) as day, SUM(meta_value) as total
            FROM {$wpdb->posts} p
            JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
            WHERE p.post_type = 'shop_order'
            AND p.post_status = 'wc-completed'
            AND pm.meta_key = '_order_total'
            GROUP BY day
            ORDER BY day DESC
            LIMIT 7",
            ARRAY_A
        );

        $bids_table = $wpdb->prefix . 'stakmv_auction_bids';
        $prepared_bids_sql = '';
        // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- Plugin-owned table name with prepared user_id value.
        $prepared_bids_sql = $wpdb->prepare(
            'SELECT DATE(created_at) as day, COUNT(*) as total FROM ' . $bids_table . ' WHERE user_id = %d GROUP BY day ORDER BY day DESC LIMIT 7',
            (int) $user_id
        );
        // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table is plugin-owned and query is read-only.
        $bids = $wpdb->get_results($prepared_bids_sql, ARRAY_A);

        return array(
            'earnings' => is_array( $earnings ) ? $earnings : array(),
            'bids'     => is_array( $bids ) ? $bids : array(),
            // Placeholder until real watchers timeseries is implemented.
            'watchers' => array( 1, 2, 3, 4, 6, 8, 12 ),
        );
    }
}
add_action('template_redirect', function () {
    $delete_listing_raw   = filter_input(INPUT_GET, 'delete_listing', FILTER_SANITIZE_NUMBER_INT);
    $relist_listing_raw   = filter_input(INPUT_GET, 'relist_listing', FILTER_SANITIZE_NUMBER_INT);
    $confirm_delivery_raw = filter_input(INPUT_POST, 'stakmv_confirm_delivery', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
    $open_dispute_raw     = filter_input(INPUT_POST, 'stakmv_open_dispute', FILTER_SANITIZE_FULL_SPECIAL_CHARS);

    if (!$delete_listing_raw && !$relist_listing_raw && !$confirm_delivery_raw && !$open_dispute_raw) {
        return;
    }

    // Delete listing
    if ($delete_listing_raw) {
        $delete_nonce = filter_input(INPUT_GET, '_wpnonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
        if (
            !$delete_nonce ||
            !wp_verify_nonce(
                sanitize_text_field((string) $delete_nonce),
                'stakmv_delete_listing'
            )
        ) {
            wp_die('Security check failed');
        }

        $post_id = absint($delete_listing_raw);
        $inv_tab_raw = filter_input(INPUT_GET, 'inv_tab', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
        $inv_tab = sanitize_key((string) ($inv_tab_raw ?: 'listings'));
        if (!in_array($inv_tab, array('listings', 'auctions'), true)) {
            $inv_tab = 'listings';
        }

        $post = get_post($post_id);

        if (!$post || (int) $post->post_author !== (int) get_current_user_id()) {
            wp_die('Unauthorized');
        }

        wp_trash_post($post_id);

        wp_safe_redirect(
            add_query_arg(
                array(
                    'tab'     => 'inventory',
                    'inv_tab' => $inv_tab,
                    'deleted' => 1,
                    'ts'      => time(),
                ),
                stakmv_get_vendor_dashboard_url()
            )
        );
        exit;
    }

    // Relist ended listing.
    if ($relist_listing_raw) {
        $relist_nonce = filter_input(INPUT_GET, '_wpnonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
        if (
            !$relist_nonce ||
            !wp_verify_nonce(
                sanitize_text_field((string) $relist_nonce),
                'stakmv_relist_listing'
            )
        ) {
            wp_die('Security check failed');
        }

        $post_id = absint($relist_listing_raw);
        $inv_tab_raw = filter_input(INPUT_GET, 'inv_tab', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
        $inv_tab = sanitize_key((string) ($inv_tab_raw ?: 'auctions'));
        if (!in_array($inv_tab, array('listings', 'auctions'), true)) {
            $inv_tab = 'auctions';
        }

        $post = get_post($post_id);
        if (!$post || (int) $post->post_author !== (int) get_current_user_id() || $post->post_type !== 'product') {
            wp_die('Unauthorized');
        }

        $status_raw = (string) get_post_meta($post_id, '_stakmv_auction_status', true);
        $status = sanitize_key($status_raw);
        if (in_array($status, array('sold', 'pending_payment'), true)) {
            wp_safe_redirect(
                add_query_arg(
                    array(
                        'tab'           => 'inventory',
                        'inv_tab'       => $inv_tab,
                        'relist_denied' => 1,
                        'ts'            => time(),
                    ),
                    stakmv_get_vendor_dashboard_url()
                )
            );
            exit;
        }

        $end_raw = get_post_meta($post_id, '_stakmv_auction_end_time', true);
        $end_ts = is_numeric($end_raw) ? (int) $end_raw : ($end_raw ? strtotime((string) $end_raw) : 0);
        $is_expired = ($end_ts > 0 && current_time('timestamp') >= $end_ts);
        $is_marked_ended = in_array($status, array('ended', 'expired'), true);
        if (!$is_expired && !$is_marked_ended) {
            wp_safe_redirect(
                add_query_arg(
                    array(
                        'tab'           => 'inventory',
                        'inv_tab'       => $inv_tab,
                        'relist_denied' => 1,
                        'ts'            => time(),
                    ),
                    stakmv_get_vendor_dashboard_url()
                )
            );
            exit;
        }

        $days = stakmv_get_relist_duration_days();
        $new_end_ts = current_time('timestamp') + ($days * DAY_IN_SECONDS);

        update_post_meta($post_id, '_stakmv_auction_end_time', $new_end_ts);
        update_post_meta($post_id, '_stakmv_auction_status', 'active');

        // Reset auction progress so a fresh bid cycle can start.
        delete_post_meta($post_id, '_stakmv_auction_current_bid');
        delete_post_meta($post_id, '_stakmv_auction_bid_count');
        delete_post_meta($post_id, '_stakmv_auction_has_bids');
        delete_post_meta($post_id, '_stakmv_auction_highest_bidder');
        delete_post_meta($post_id, '_stakmv_auction_winner');
        delete_post_meta($post_id, '_stakmv_auction_failed_bidder');
        delete_post_meta($post_id, '_stakmv_auction_payment_deadline');
        delete_post_meta($post_id, '_stakmv_auction_extensions_used');

        // Restore live displayed price to start price for auction-only listings.
        $listing_type = sanitize_key((string) get_post_meta($post_id, '_stakmv_auction_listing_type', true));
        if ($listing_type === 'auction_only' || $listing_type === '') {
            $start_price = wc_format_decimal(get_post_meta($post_id, '_stakmv_auction_start_price', true));
            if ($start_price !== '') {
                update_post_meta($post_id, '_regular_price', $start_price);
                update_post_meta($post_id, '_price', $start_price);
            }
        }

        global $wpdb;
        if (defined('STAKMV_AUCTION_BIDS_TABLE')) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- Intentional cleanup write during relist.
            $wpdb->delete(STAKMV_AUCTION_BIDS_TABLE, array('auction_id' => $post_id), array('%d'));
        }

        wp_safe_redirect(
            add_query_arg(
                array(
                    'tab'      => 'inventory',
                    'inv_tab'  => $inv_tab,
                    'relisted' => 1,
                    'ts'       => time(),
                ),
                stakmv_get_vendor_dashboard_url()
            )
        );
        exit;
    }

    // Confirm delivery (buyer action)
    if ($confirm_delivery_raw) {
        $confirm_delivery_nonce = filter_input(INPUT_POST, 'stakmv_confirm_delivery_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
        if (
            !$confirm_delivery_nonce ||
            !wp_verify_nonce(
                sanitize_text_field((string) $confirm_delivery_nonce),
                'stakmv_confirm_delivery'
            )
        ) {
            wp_die('Security check failed');
        }

        $order_id = absint(filter_input(INPUT_POST, 'order_id', FILTER_SANITIZE_NUMBER_INT));
        if (!$order_id) {
            wp_die('Security check failed');
        }

        if (!is_user_logged_in()) {
            wp_die('Not allowed');
        }

        $order = wc_get_order($order_id);
        if (!$order || (int) $order->get_user_id() !== (int) get_current_user_id()) {
            wp_die('Unauthorized');
        }

        update_post_meta($order_id, '_stakmv_buyer_confirmed', 'yes');

        // Attempt auto-approve if pending
        if (function_exists('stakmv_approve_escrow')) {
            $status = get_post_meta($order_id, '_stakmv_escrow_status', true);
            if ($status === 'pending') {
                stakmv_approve_escrow($order_id);
            }
        }

        // Notify vendor and admin
        $auction_id = $order->get_meta('_stakmv_auction_id');
        $vendor_id  = $auction_id ? (int) get_post_field('post_author', $auction_id) : 0;

        if ($vendor_id) {
            $vendor = get_user_by('id', $vendor_id);
            if ($vendor) {
                wp_mail(
                    $vendor->user_email,
                    'Buyer confirmed delivery',
                    'The buyer has confirmed delivery for their order #' . $order_id . '.'
                );
            }
        }

        wp_mail(
            get_option('admin_email'),
            'Buyer confirmed delivery',
            'Order #' . $order_id . ' was confirmed by the buyer.'
        );

        wp_safe_redirect(wp_get_referer());
        exit;
    }

    // Open dispute (buyer action)
    if ($open_dispute_raw) {
        $open_dispute_nonce = filter_input(INPUT_POST, 'stakmv_open_dispute_nonce', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
        if (
            !$open_dispute_nonce ||
            !wp_verify_nonce(
                sanitize_text_field((string) $open_dispute_nonce),
                'stakmv_open_dispute'
            )
        ) {
            wp_die('Security check failed');
        }

        $order_id = absint(filter_input(INPUT_POST, 'order_id', FILTER_SANITIZE_NUMBER_INT));
        if (!$order_id) {
            wp_die('Security check failed');
        }

        if (!is_user_logged_in()) {
            wp_die('Not allowed');
        }

        $order = wc_get_order($order_id);
        if (!$order || (int) $order->get_user_id() !== (int) get_current_user_id()) {
            wp_die('Unauthorized');
        }

        // Create a lightweight "ticket" as an order comment
        $comment_id = wp_insert_comment(array(
            'comment_post_ID'      => $order_id,
            'comment_author'       => wp_get_current_user()->display_name,
            'comment_author_email' => wp_get_current_user()->user_email,
            'comment_content'      => 'Dispute opened by buyer.',
            'comment_type'         => 'stakmv_dispute',
            'user_id'              => get_current_user_id(),
            'comment_approved'     => 1,
        ));

        if ($comment_id) {
            add_comment_meta($comment_id, '_stakmv_dispute_status', 'open');
        }

        // Notify vendor and admin
        $auction_id = $order->get_meta('_stakmv_auction_id');
        $vendor_id  = $auction_id ? (int) get_post_field('post_author', $auction_id) : 0;

        if ($vendor_id) {
            $vendor = get_user_by('id', $vendor_id);
            if ($vendor) {
                wp_mail(
                    $vendor->user_email,
                    'New dispute opened',
                    'The buyer has opened a dispute for order #' . $order_id . '.'
                );
            }
        }

        wp_mail(
            get_option('admin_email'),
            'New dispute opened',
            'A dispute was opened for order #' . $order_id . '.'
        );

        wp_safe_redirect(wp_get_referer());
        exit;
    }
    // phpcs:enable WordPress.Security.NonceVerification.Recommended
});
function stakmv_get_create_listing_url() {
    $page_id = stakmv_get_option('create_listing_page');
    if ($page_id) {
        return get_permalink($page_id);
    }
    return '#';
}

function stakmv_get_browse_listings_url() {
    $page_id = (int) stakmv_get_option('browse_listings_page');
    if ($page_id > 0 && get_post_status($page_id) === 'publish') {
        $url = get_permalink($page_id);
        if ($url) {
            return $url;
        }
    }

    $shop_id = (int) wc_get_page_id('shop');
    if ($shop_id > 0 && get_post_status($shop_id) === 'publish') {
        $url = get_permalink($shop_id);
        if ($url) {
            return $url;
        }
    }

    return home_url('/');
}

function stakmv_get_vendor_dashboard_url() {
    static $resolved = null;

    if (null !== $resolved) {
        return $resolved;
    }

    $fallback = site_url('/vendor-dashboard');

    $configured_id = (int) stakmv_get_option('vendor_dashboard_page');
    if ($configured_id > 0 && get_post_status($configured_id) === 'publish') {
        $resolved = get_permalink($configured_id);
        return $resolved ?: $fallback;
    }

    $cached_id = (int) stakmv_get_transient('vendor_dashboard_page_id');
    if ($cached_id > 0 && get_post_status($cached_id) === 'publish') {
        $resolved = get_permalink($cached_id);
        return $resolved ?: $fallback;
    }

    $page_ids = get_posts(array(
        'post_type'      => 'page',
        'post_status'    => 'publish',
        'posts_per_page' => -1,
        'fields'         => 'ids',
    ));

    foreach ((array) $page_ids as $page_id) {
        $content = get_post_field('post_content', $page_id);
        if ($content && has_shortcode($content, 'stakmv-vendor-dashboard')) {
            stakmv_set_transient('vendor_dashboard_page_id', (int) $page_id, DAY_IN_SECONDS);
            $resolved = get_permalink($page_id);
            return $resolved ?: $fallback;
        }
    }

    $resolved = $fallback;
    return $resolved;
}

function stakmv_get_apply_vendor_url() {
    static $resolved = null;

    if (null !== $resolved) {
        return $resolved;
    }

    $fallback = stakmv_get_vendor_dashboard_url();
    $cached_id = (int) stakmv_get_transient('apply_vendor_page_id');
    if ($cached_id > 0 && get_post_status($cached_id) === 'publish') {
        $resolved = get_permalink($cached_id);
        return $resolved ?: $fallback;
    }

    $page_ids = get_posts(array(
        'post_type'      => 'page',
        'post_status'    => 'publish',
        'posts_per_page' => -1,
        'fields'         => 'ids',
    ));

    foreach ((array) $page_ids as $page_id) {
        $content = get_post_field('post_content', $page_id);
        if ($content && has_shortcode($content, 'stakmv-apply-vendor')) {
            stakmv_set_transient('apply_vendor_page_id', (int) $page_id, DAY_IN_SECONDS);
            $resolved = get_permalink($page_id);
            return $resolved ?: $fallback;
        }
    }

    $resolved = $fallback;
    return $resolved;
}

/**
 * AJAX: Return attribute fields HTML for a given category.
 * Honors configured category mappings. Falls back to all attributes if no mapping exists.
 *
 * Enhanced: renders cascading selects for graphics card brand -> model.
 */
add_action( 'wp_ajax_stakmv_get_category_attrs', 'stakmv_get_category_attrs' );
function stakmv_get_category_attrs() {
	check_ajax_referer( 'stakmv_cl_nonce' );

	if ( ! is_user_logged_in() || ( function_exists( 'stakmv_is_vendor' ) && ! stakmv_is_vendor( get_current_user_id() ) ) ) {
		wp_send_json_error( array( 'message' => 'Not allowed' ), 403 );
	}

	$cat_id     = absint( filter_input( INPUT_POST, 'cat_id', FILTER_SANITIZE_NUMBER_INT ) );
	$product_id = absint( filter_input( INPUT_POST, 'product_id', FILTER_SANITIZE_NUMBER_INT ) );

	$taxonomies         = wc_get_attribute_taxonomies();
	$allowed_taxonomies = $cat_id ? (array) get_term_meta( $cat_id, 'stakmv_cat_attrs', true ) : array();

	// Resolve selected terms for edit mode.
	$selected_terms_by_tax = array();
	if ( $product_id ) {
		if ( ! empty( $taxonomies ) ) {
			foreach ( $taxonomies as $attr ) {
				$tax      = 'pa_' . $attr->attribute_name;
				$selected = wp_get_post_terms( $product_id, $tax, array( 'fields' => 'ids' ) );
				if ( ! is_wp_error( $selected ) ) {
					$selected_terms_by_tax[ $tax ] = array_map( 'intval', $selected );
				}
			}
		}
	}

	// Helper: get selected model and derive selected brand (if any)
	$selected_graphics_model = 0;
	$preselected_graphics_brand = 0;
	if ( ! empty( $selected_terms_by_tax['pa_graphics-card-model'] ) ) {
		$selected_graphics_model = (int) $selected_terms_by_tax['pa_graphics-card-model'][0];
		$parent_brand = get_term_meta( $selected_graphics_model, 'parent_brand', true );
		if ( $parent_brand ) {
			// Find brand term by slug in the graphics-card-brand taxonomy
			$brand_term = get_term_by( 'slug', sanitize_title( $parent_brand ), 'pa_graphics-card-brand' );
			if ( $brand_term && ! is_wp_error( $brand_term ) ) {
				$preselected_graphics_brand = (int) $brand_term->term_id;
			}
		}
	} elseif ( ! empty( $selected_terms_by_tax['pa_graphics-card-brand'] ) ) {
		$preselected_graphics_brand = (int) $selected_terms_by_tax['pa_graphics-card-brand'][0];
	}

	ob_start();
	echo '<div class="wcmv-form-grid">';

	if ( ! empty( $taxonomies ) ) {
		foreach ( $taxonomies as $attr ) {
			$tax = 'pa_' . $attr->attribute_name;

			if ( ! empty( $allowed_taxonomies ) && ! in_array( $tax, $allowed_taxonomies, true ) ) {
				continue;
			}

			// Special rendering for Graphics Card Brand -> render as single select
			if ( $tax === 'pa_graphics-card-brand' ) {

				$terms = get_terms( array(
					'taxonomy'   => $tax,
					'hide_empty' => false,
				) );

				if ( is_wp_error( $terms ) || empty( $terms ) ) {
					continue;
				}

				echo '<div class="wcmv-field">';
				echo '<label>' . esc_html( wc_attribute_label( $tax ) ) . '</label>';

				// Single-select; value = term_id so listing-save can use numeric IDs
				echo '<select id="wcmv-attr-graphics-brand" name="attrs[' . esc_attr( $tax ) . ']" class="widefat">';
				echo '<option value="">' . esc_html__( 'Select Brand', 'stak-multivendor' ) . '</option>';
				foreach ( $terms as $t ) {
					printf(
						'<option value="%1$d"%2$s>%3$s</option>',
						(int) $t->term_id,
						selected( (int) $t->term_id, (int) $preselected_graphics_brand, false ),
						esc_html( $t->name )
					);
				}
				echo '</select>';

				echo '</div>';

				// Render an initially empty/disabled model select. It will be populated via AJAX
				echo '<div class="wcmv-field">';
				echo '<label>' . esc_html( wc_attribute_label( 'pa_graphics-card-model' ) ) . '</label>';
				echo '<select id="wcmv-attr-graphics-model" name="attrs[pa_graphics-card-model]" class="widefat" disabled>';
				if ( $preselected_graphics_brand && $selected_graphics_model ) {
					// If editing and we have a preselected model & brand, populate server-side
					// by fetching models for the brand and marking selected.
					$brand_term = get_term( $preselected_graphics_brand, 'pa_graphics-card-brand' );
					$brand_slug = $brand_term ? $brand_term->slug : '';
					$models = get_terms( array(
						'taxonomy'   => 'pa_graphics-card-model',
						'hide_empty' => false,
					) );
					if ( ! is_wp_error( $models ) && ! empty( $models ) ) {
						foreach ( $models as $m ) {
							$parent = get_term_meta( $m->term_id, 'parent_brand', true );
							if ( $parent && sanitize_title( $parent ) === sanitize_title( $brand_slug ) ) {
									printf(
										'<option value="%1$d"%2$s>%3$s</option>',
										(int) $m->term_id,
										selected( (int) $m->term_id, (int) $selected_graphics_model, false ),
										esc_html( $m->name )
									);
							}
						}
						// enable if there was at least one option
						if ( $selected_graphics_model ) {
							echo ''; // options already printed above
						}
					}
				}
				echo '</select>';
				echo '</div>';

				continue;
			}

			// Default rendering: checkbox list (keeps original behaviour)
			$terms = get_terms( array(
				'taxonomy'   => $tax,
				'hide_empty' => false,
			) );
			if ( is_wp_error( $terms ) || empty( $terms ) ) {
				continue;
			}

			echo '<div class="wcmv-field">';
			echo '<label>' . esc_html( wc_attribute_label( $tax ) ) . '</label>';

			foreach ( $terms as $t ) {
				$is_checked = isset( $selected_terms_by_tax[ $tax ] ) && in_array( (int) $t->term_id, (array) $selected_terms_by_tax[ $tax ], true );
				echo '<label class="wcmv-attr-option">';
				printf(
					'<input type="checkbox" name="attrs[%1$s][]" value="%2$s"%3$s>',
					esc_attr( $tax ),
					(int) $t->term_id,
					checked( $is_checked, true, false )
				);
				echo esc_html( $t->name );
				echo '</label>';
			}

			echo '</div>';
		}
	}

	echo '</div>';
	$html = ob_get_clean();

	wp_send_json_success( array( 'html' => $html ) );
}

/**
 * AJAX: Return GPU model options for a given Graphics Card Brand.
 * Expects:
 *  - brand_id (int) : term_id of pa_graphics-card-brand
 *  - product_id (optional int) : to mark selected model in edit mode
 */
add_action( 'wp_ajax_stakmv_get_gpu_models', 'stakmv_get_gpu_models' );
function stakmv_get_gpu_models() {
	check_ajax_referer( 'stakmv_cl_nonce' );

	if ( ! is_user_logged_in() || ( function_exists( 'stakmv_is_vendor' ) && ! stakmv_is_vendor( get_current_user_id() ) ) ) {
		wp_send_json_error( array( 'message' => 'Not allowed' ), 403 );
	}

	$brand_id   = absint( filter_input( INPUT_POST, 'brand_id', FILTER_SANITIZE_NUMBER_INT ) );
	$product_id = absint( filter_input( INPUT_POST, 'product_id', FILTER_SANITIZE_NUMBER_INT ) );

	if ( $brand_id <= 0 ) {
		wp_send_json_error( array( 'message' => 'Invalid brand' ), 400 );
	}

	$brand_term = get_term( $brand_id, 'pa_graphics-card-brand' );
	if ( ! $brand_term || is_wp_error( $brand_term ) ) {
		wp_send_json_error( array( 'message' => 'Brand not found' ), 404 );
	}

	$brand_slug = $brand_term->slug;

	$models = get_terms( array(
		'taxonomy'   => 'pa_graphics-card-model',
		'hide_empty' => false,
	) );

	if ( is_wp_error( $models ) || empty( $models ) ) {
		wp_send_json_success( array( 'html' => '<option value="">' . esc_html__( 'No models available', 'stak-multivendor' ) . '</option>' ) );
	}

	// If editing, determine selected model (if any)
	$selected_model_id = 0;
	if ( $product_id ) {
		$selected = wp_get_post_terms( $product_id, 'pa_graphics-card-model', array( 'fields' => 'ids' ) );
		if ( ! is_wp_error( $selected ) && ! empty( $selected ) ) {
			$selected_model_id = (int) $selected[0];
		}
	}

	$options_html = '<option value="">' . esc_html__( 'Select Model', 'stak-multivendor' ) . '</option>';
	foreach ( $models as $m ) {
		$parent = get_term_meta( $m->term_id, 'parent_brand', true );
		if ( $parent && sanitize_title( $parent ) === sanitize_title( $brand_slug ) ) {
			$sel = $selected_model_id && ( (int) $m->term_id === $selected_model_id ) ? ' selected' : '';
			$options_html .= sprintf( '<option value="%d"%s>%s</option>', (int) $m->term_id, $sel, esc_html( $m->name ) );
		}
	}

	if ( $options_html === '<option value="">' . esc_html__( 'Select Model', 'stak-multivendor' ) . '</option>' ) {
		$options_html = '<option value="">' . esc_html__( 'No models available', 'stak-multivendor' ) . '</option>';
	}

	wp_send_json_success( array( 'html' => $options_html ) );
}
