<?php

namespace auctionforge\inc\controllers;

use auctionforge\inc\BidSpiritRequest;
use auctionforge\inc\Debug;
use auctionforge\inc\helpers\BS_API;
use auctionforge\inc\helpers\Conditions;
use auctionforge\inc\helpers\LotHelper;
use auctionforge\inc\helpers\SettingsHelper;
use auctionforge\inc\helpers\View;
use auctionforge\inc\InstanceDB;
use auctionforge\inc\model\Auction;
use auctionforge\inc\model\Lot;
use auctionforge\inc\model\LotMetaData;
use WP_Post;
use WP_Query;
use WP_Term;

class BidspiritLots
{
    const POST_TYPE = 'lot';
    const TAX_AUCTION_TYPE = 'auction_number';
    const TAX_TAGS_TYPE = 'auction_tag';
    const PREFIX_FIELD = 'auction_';
    const TYPE_FIELD_TEXT = 'text';
    const TYPE_FIELD_TEXTAREA = 'textarea';
    const TYPE_FIELD_CHECKBOX = 'checkbox';
    const LABEL_DISABLED = 'disabled';
    const LABEL_PRICE = 'price';
    const LABEL = 'label';
    const LABELS = 'labels';
    const VALUE = 'value';
    const DESCRIPTION = 'description';
    const TYPE = 'type';
    const LABEL_CLASS = 'class';
    const LABEL_TAXONOMY = 'taxonomy';
    const PARAM_CATEGORY_BY = "bp_param_category_by";
    const PARAM_S = "bp_param_s";
    const PARAM_PER_PAGE = "bp_param_per_page";
    const PARAM_PAGED = "paged";

    const BACK_DOMAIN = 'auctionforge';

    const AUCTIONFORGE_ORDER_FIELD = 'auctionforge_order_field';
    const AUCTIONFORGE_ORDERBY_FIELDS = 'auctionforge_orderby_fields';

    private $fields = array();
    private $checkboxField = array();
    static $imageSizes = array(
        'lot-thumbnail-min',
        'lot-thumbnail',
        'lot-slide',
    );

    /**
     * Binding action and filters in the system.
     * @return void
     */
    public function init()
    {
        add_action('init', array($this, 'create_post_type__lot'), 0);
        add_action('init', array($this, 'bp_session_starter'));
        add_action('save_post_' . self::POST_TYPE, array($this, 'purge_lot_on_save'), 20, 1);

        add_action('wp', array($this, 'polylang_lang'), 3);
        add_action('auction_number_edit_form_fields', array($this, 'bidspirit_taxonomy_edit_custom_meta_field'), 10, 2);
        add_action('edited_auction_number', array($this, 'bidspirit_save_taxonomy_custom_meta_field'), 10, 2);
        add_action('create_auction_number', array($this, 'bidspirit_save_taxonomy_custom_meta_field'), 10, 2);

        add_action('init', array($this, 'post_tag_for_pages'));

        add_filter('wp_insert_post_parent', array($this, 'set_post_parent'), 11, 4);

        add_filter('wp_insert_post_data', array($this, 'bp_insert_post_data'), 10, 3);

        add_filter('post_type_link', array($this, 'auction_permalink'), 1, 2);

        add_filter('post_type_link', array($this, 'polylang_link'), 10, 4);
        add_filter('term_link', array($this, 'polylang_term_link'), 1, 4);

        // Single-lot auctions: link directly to the lot page
        add_filter('term_link', array($this, 'single_lot_term_link'), 20, 3);
        add_action('template_redirect', array($this, 'redirect_single_lot_auction'), 5);

        add_filter('intermediate_image_sizes', array($this, 'true_reduce_image_sizes'), 10, 1);

        add_filter('lots_pagination_settings', array($this, 'lots_pagination_settings'), 10, 1);

        add_action('delete_post', array($this, 'bp_meta_data_sync'), 10, 1);

        /**
         * Sorting lots
         */
        add_filter('manage_lot_posts_columns', array($this, 'lot_filter_columns'));
        add_action('manage_lot_posts_custom_column', array($this, 'lot_realestate_column'), 10, 2);
        add_filter('manage_edit-lot_sortable_columns', array($this, 'bidspirit_lot_sortable_columns'));
        add_action('pre_get_posts', array($this, 'bidspirit_lot_orderby'));

        add_action('pre_get_posts', array($this, 'search_filter'));

        add_action('pre_get_posts', [$this, 'handle_empty_filter_results'], 5, 1);

        add_action('pre_get_posts', array($this, 'bidspirit_lot_per_page'));

        add_action('pre_get_posts', array($this, 'bidspirit_lot_solds'));

        add_action('pre_get_posts', array($this, 'refresh_leading_bids_for_sort'), 1);

        add_filter('navigation_markup_template', array($this, 'clear_h2_from_navigation'), 10, 2);

        add_filter('auctionforge_prepare_auction_object', array($this, 'prepare_auction_object'));

        add_action('wp_loaded', array($this, 'check_is_live'), 0);

        add_filter('manage_edit-auction_number_columns', array($this, 'add_auction_id_columns'));
        add_filter('manage_auction_number_custom_column', array($this, 'add_auction_number_column_content'), 10, 3);

        add_action('bp_auto_close', array(__CLASS__, 'bidspirit_auto_close_action'), 10, 1);
        // Clean up bp_auto_close cron events when their auction term is deleted —
        // before 3.7.0.28 these accumulated for every auction that ever ran on
        // the site (no unschedule path), inflating wp_options.cron without bound.
        add_action('pre_delete_term', array(__CLASS__, 'cleanup_auto_close_on_term_delete'), 10, 2);

        add_filter('auctionforge_query_auction_params', array($this, 'query_manual_auction_params'), 10, 1);
        add_filter('auctionforge_query_auction_params', array($this, 'query_hidden_auction_params'), 10, 1);
        add_filter('auctionforge_query_auction_params_sync', array($this, 'query_sync_auction_params'), 10, 1);

        add_filter('auctionforge_query_auction_params', array($this, 'query_auction_params'), 10, 1);

        add_filter('auctionforge_auction_name_build', array($this, 'auction_title_build'), 10, 2);
        add_filter('document_title_parts', array($this, 'fix_auction_seo_title'), 10, 1);
        add_action('wp_head', array($this, 'insert_image_opengraph'), 5);

        add_action('bs_bidFormSection_action', array($this, 'showcase_action'), 10, 2);

        add_action('wp_login', [$this, 'set_nonce_cookies']);

        add_action('template_redirect', [$this, 'maybe_redirect_to_first_page'], 0);
        add_action('template_redirect', [$this, 'redirect_excess_pagination'], 10);

        $this->setFields();
        $this->setCheckboxFields();
    }

    /**
     * For single-lot auctions, rewrite the term link to point directly to the lot page.
     *
     * @param string $termlink The original term link URL.
     * @param WP_Term $term The term object.
     * @param string $taxonomy The taxonomy slug.
     * @return string Modified link pointing to the lot when the auction has exactly 1 lot.
     */
    public function single_lot_term_link($termlink, $term, $taxonomy) {
        if ($taxonomy !== self::TAX_AUCTION_TYPE) {
            return $termlink;
        }

        // Skip in admin context
        if (is_admin()) {
            return $termlink;
        }

        // Use WordPress cached count from the term object
        if (!isset($term->count) || intval($term->count) !== 1) {
            return $termlink;
        }

        // Fetch the single lot post for this auction
        $lots = get_posts(array(
            'post_type'      => self::POST_TYPE,
            'posts_per_page' => 1,
            'post_status'    => 'publish',
            'tax_query'      => array(
                array(
                    'taxonomy' => self::TAX_AUCTION_TYPE,
                    'field'    => 'term_id',
                    'terms'    => $term->term_id,
                ),
            ),
            'suppress_filters' => true,
        ));

        if (!empty($lots) && count($lots) === 1) {
            return get_permalink($lots[0]->ID);
        }

        return $termlink;
    }

    /**
     * If a visitor lands on the catalog page of a single-lot auction,
     * 301-redirect them to the lot page.
     */
    public function redirect_single_lot_auction() {
        if (!is_tax(self::TAX_AUCTION_TYPE)) {
            return;
        }

        $term = get_queried_object();
        if (!($term instanceof WP_Term)) {
            return;
        }

        if (intval($term->count) !== 1) {
            return;
        }

        $lots = get_posts(array(
            'post_type'      => self::POST_TYPE,
            'posts_per_page' => 1,
            'post_status'    => 'publish',
            'tax_query'      => array(
                array(
                    'taxonomy' => self::TAX_AUCTION_TYPE,
                    'field'    => 'term_id',
                    'terms'    => $term->term_id,
                ),
            ),
            'suppress_filters' => true,
        ));

        if (!empty($lots) && count($lots) === 1) {
            wp_redirect(get_permalink($lots[0]->ID), 301);
            exit;
        }
    }

    public function set_nonce_cookies() {
        $cookie_name = 'rest_nonce';
        $cookie_value = wp_create_nonce('wp_rest');
        $cookie_exp = 0;
        $cookie_path = "/";
        $cookie_domain = "";
        $cookie_secure = true;
        $cookie_http_only = false;
        setcookie($cookie_name, $cookie_value, $cookie_exp, $cookie_path, $cookie_domain, $cookie_secure, $cookie_http_only);
    }

    /**
     * Start a PHP session only when this request actually needs one. Starting a
     * session emits no-cache headers, so for fresh anonymous page views (which
     * carry no catalog state to remember) we skip it and let the page be cached.
     * Logged-in users, returning visitors that already hold a session, and any
     * filter/search/pagination request still get one. Shared by the init
     * starter and the on-demand filter/pagination handlers.
     *
     * @return bool true if a session is active after the call
     */
    private function maybe_start_session()
    {
        if (session_status() === PHP_SESSION_ACTIVE) {
            return true;
        }
        if (headers_sent() || session_id()) {
            return session_status() === PHP_SESSION_ACTIVE;
        }

        $has_state_params =
            !empty($_GET[Lot::NAME_PARAM_CATEGORY])
            || !empty($_GET[Lot::NAME_PARAM_PHRASE])
            || !empty($_GET[Lot::NAME_PARAM_PER_PAGE])
            || !empty($_GET[Lot::NAME_PARAM_IS_SOLD])
            || !empty($_GET['paged']);

        $request_method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';

        $needs_session =
            is_user_logged_in()
            || isset($_COOKIE[session_name()])
            || $has_state_params
            || ($request_method !== 'GET' && $request_method !== 'HEAD');

        /**
         * Override whether AuctionForge starts a session for this request.
         * Return true to force a session (disables page caching for the
         * request), false to skip it.
         *
         * @param bool $needs_session
         */
        $needs_session = apply_filters('auctionforge_needs_session', $needs_session);

        if ($needs_session) {
            @session_start();
        }

        return session_status() === PHP_SESSION_ACTIVE;
    }

    public function bp_session_starter()
    {
        if (!$this->maybe_start_session()) {
            // No session for this request -> the page stays cacheable.
            return;
        }

        if (!isset($_SESSION[self::PARAM_CATEGORY_BY])) {
            $_SESSION[self::PARAM_CATEGORY_BY] = null;
        }
        if (!isset($_SESSION[self::PARAM_S])) {
            $_SESSION[self::PARAM_S] = null;
        }
        if (!isset($_SESSION[self::PARAM_PAGED])) {
            $_SESSION[self::PARAM_PAGED] = 1;
        }
        if (!isset($_SESSION[self::PARAM_PER_PAGE])) {
            $_SESSION[self::PARAM_PER_PAGE] = get_option('posts_per_page', 10);
        }

        // Release the session lock immediately so REST API and loopback requests are not blocked.
        session_write_close();
    }

    /**
     * Purge a lot's cached page(s) when it is edited in wp-admin. Lots changed
     * by the BidSpirit sync are already handled by the importer, so skip during
     * a sync run (and ignore autosaves/revisions).
     *
     * @param int $postId
     */
    public function purge_lot_on_save($postId)
    {
        if (!empty($_SERVER['AUCTIONFORGE_IMPORT_LOT'])
            || (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
            || wp_is_post_revision($postId)) {
            return;
        }
        CachePurge::purgeLot((int) $postId);
    }

    /**
     * @param $object WP_Term
     * @return mixed
     */
    public function prepare_auction_object($object)
    {
        if ($object instanceof WP_Term && PolylangSupport::isPolylangActive() && PolylangSupport::isFullSupport()) {
            $defaultLang = MultiLanguageSupport::getDefaultLangCode();
            $secondLang = MultiLanguageSupport::getSecondLangCode();
            $pattern = "/(\s|\-)(" . $defaultLang . "|" . $secondLang . ")/";
            $object->name = preg_replace($pattern, "", $object->name);
        }
        return $object;
    }

    public function check_is_live()
    {
        $args = array(
            'post_type' => BidspiritLots::POST_TYPE,
            'taxonomy' => BidspiritLots::TAX_AUCTION_TYPE,
            'hide_empty' => 1,
            'meta_query' => array(
                'relation' => 'AND',
                array(
                    'key' => 'auction_state',
                    'value' => array(Auction::STATE_RUNNING),
                    'compare' => 'IN'
                )
            ),
        );
        if (PolylangSupport::isFullSupport()) {
            $args = array_merge($args, array(
                'lang' => SettingsHelper::getOption('lang', 'en')
            ));
        }
        $runAuctions = get_terms($args);
        if (!empty($runAuctions)) {
            foreach ($runAuctions as $auction) {
                $attr = array();
                $attr['term_id'] = $auction->term_id;
                $attr['slug'] = $auction->slug;

                if (!wp_next_scheduled('bp_auto_close', $attr)) {
                    wp_schedule_event(time(), 'bp_ten_minutely', 'bp_auto_close', $attr);
                }
            }
        }
    }

    function add_auction_id_columns($columns)
    {
        $table = array(
            'cb' => $columns['cb'] ?? "Cb",
            'name' => __('Name'),
            'auction_id' => 'Bidspirit ID'
        );
        return wp_parse_args($columns, $table);
    }

    public function add_auction_number_column_content($content, $column_name, $term_id)
    {
        switch ($column_name) {
            case 'auction_id':
                $content = SettingsHelper::getTermOption($term_id, 'auction_id', '');
                break;
            default:
                break;
        }
        return $content;
    }

    /**
     * @param $auction string
     */
    public static function bidspirit_auto_close_action($auction) {
        // Self-clean: if the term has gone away (deleted while this cron sat
        // queued, or stale from before the pre_delete_term hook landed in
        // 3.7.0.28), unschedule and bail. Without this, dangling per-term
        // events poll the BidSpirit API forever.
        $term = get_term($auction, self::TAX_AUCTION_TYPE);
        if (!$term || is_wp_error($term)) {
            self::unschedule_auto_close($auction);
            return;
        }

        $auctionId = SettingsHelper::getTermOption($auction, "auction_id");
        $response = BidSpiritRequest::send("auctions/getAuctionInfo.api", array(
            "auctionId" => intval($auctionId),
            "language" => SettingsHelper::getOption("lang", "en")
        ));

        if ($response['response']) {
            $response = json_decode($response['response']);
            if (!empty($response->response->state)) {
                $remoteState = $response->response->state;
                if ($remoteState == Auction::STATE_ENDING) {
                    update_term_meta($auction, 'auction_state', $remoteState);
                }
                // Self-clean: once the upstream auction is no longer running OR
                // ending, the 10-minutely poll has no work left to do. Drop the
                // scheduled event so we don't accumulate forever.
                //
                // Also write the remote state to local meta. Otherwise
                // check_is_live() — which runs on every wp_loaded and queries
                // terms with auction_state = STATE_RUNNING — would immediately
                // re-arm the cron we just unscheduled. Writing the meta is
                // consistent with what SafetySync::run() and the import
                // pipeline (inc/import/AuctionList.php:229) already do when
                // they observe a non-RUNNING upstream state.
                if ($remoteState != Auction::STATE_RUNNING && $remoteState != Auction::STATE_ENDING) {
                    update_term_meta($auction, 'auction_state', $remoteState);
                    self::unschedule_auto_close($auction, $term->slug);
                }
            }
        }
    }

    /**
     * Unschedule the bp_auto_close event for a given term.
     *
     * Args must match the original wp_schedule_event() call exactly
     * (signature is md5(serialize($args))), so we reconstruct the same
     * ['term_id' => ..., 'slug' => ...] shape used at scheduling time.
     *
     * @param int         $term_id The taxonomy term id.
     * @param string|null $slug    Optional slug; resolved from the term if omitted.
     */
    public static function unschedule_auto_close($term_id, $slug = null) {
        if ($slug === null) {
            $term = get_term($term_id, self::TAX_AUCTION_TYPE);
            // Term gone? Best-effort: clear every variant we can construct.
            // We can't reconstruct the original slug, so fall back to clearing
            // anything matching just the term_id under a few common slug values
            // (empty + the term_id stringified) — this is a tidy-up, not a
            // correctness guarantee. The cron-cleanup migration sweeps the
            // remaining orphans on the next upgrade pass anyway.
            if (!$term || is_wp_error($term)) {
                wp_clear_scheduled_hook('bp_auto_close', array('term_id' => $term_id, 'slug' => ''));
                wp_clear_scheduled_hook('bp_auto_close', array('term_id' => $term_id, 'slug' => (string) $term_id));
                return;
            }
            $slug = $term->slug;
        }
        wp_clear_scheduled_hook('bp_auto_close', array('term_id' => $term_id, 'slug' => $slug));
    }

    /**
     * pre_delete_term hook — drop any pending bp_auto_close event when the
     * auction's taxonomy term is deleted, so a deleted auction can't leave a
     * 10-minutely poll behind forever.
     *
     * @param int    $term     The term id being deleted.
     * @param string $taxonomy The taxonomy slug.
     */
    public static function cleanup_auto_close_on_term_delete($term, $taxonomy) {
        if ($taxonomy !== self::TAX_AUCTION_TYPE) {
            return;
        }
        self::unschedule_auto_close($term);
    }

    public function query_manual_auction_params($args)
    {
        global $post;

        if (empty($post->ID)) {
            return $args;
        }

        $manualPolylangId = 0;
        $pageArchiveListKey = SettingsHelper::getOption('archive_list', 0);
        $pageManualListKey = SettingsHelper::getOption('manual_auction_list', 0);
        $archivePolylangId = 0;
        if (PolylangSupport::isPolylangActive()) {
            $lang = pll_current_language();
            $archivePolylangId = pll_get_post($pageArchiveListKey, $lang);
            $manualPolylangId = pll_get_post($pageManualListKey, $lang);
        }
        $isManual = ($post->ID == $pageManualListKey || $post->ID == $manualPolylangId);
        $isArchived = ($post->ID == $pageArchiveListKey || $post->ID == $archivePolylangId);
        if ($pageManualListKey && !$isArchived) {
            if ($isManual) {
                $manual = array(
                    'key' => 'auction_automaticAuction',
                    'value' => 'false',
                    'compare' => '='
                );
            } else {
                $manual = array(
                    'key' => 'auction_automaticAuction',
                    'value' => 'true',
                    'compare' => '='
                );
            }
            $args['meta_query'][] = $manual;
        }

        return $args;
    }

    function query_hidden_auction_params($args) {
        $hiddenAuctions = SettingsHelper::getAuctionListFromSettings('hidden_auction');
        $shopAuctions = SettingsHelper::getAuctionListFromSettings('shop_auction');
        $hiddenAuctions = array_merge($hiddenAuctions, $shopAuctions);
        $args['exclude'] = $hiddenAuctions;

        return $args;
    }

    function query_sync_auction_params($args) {
        $hiddenAuctions = SettingsHelper::getAuctionListFromSettings('hidden_auction');
        $args['exclude'] = $hiddenAuctions;

        return $args;
    }

    public function query_auction_params($params)
    {
        $relTemplatePath = get_stylesheet_directory() . "/auctionforge/main/auction_list.php";
        $fileInfo = auctionforge_plugin_file_info($relTemplatePath);

        if (file_exists($relTemplatePath)) {
            if (!empty($fileInfo) && $fileInfo['ver'] == '2.0') {
                unset($params['meta_query']);
            } else {
                return $params;
            }
        } else {
            unset($params['meta_query']);
        }

        return $params;
    }

    public function true_reduce_image_sizes($sizes)
    {
        if (!empty($_SERVER['AUCTIONFORGE_IMPORT_LOT']) && $_SERVER['AUCTIONFORGE_IMPORT_LOT']) {
            return BidspiritLots::$imageSizes;
        } else {
            return array_diff($sizes, BidspiritLots::$imageSizes);
        }
    }

    public function lots_pagination_settings($settings)
    {
        $settings = array_merge($settings, [
            'prev_text' => _x('Previous', 'previous set of lots', 'auctionforge'),
            'next_text' => _x('Next', 'next set of lots', 'auctionforge'),
            'screen_reader_text' => __('Lots navigation', 'auctionforge'),
            'aria_label' => __('Lots', 'auctionforge')
        ]);

        return $settings;
    }

    public function bidspirit_admin_init()
    {
        add_action('delete_post', array($this, 'bp_meta_data_sync'), 10, 1);
    }

    public function bp_meta_data_sync($postId)
    {
        $db = InstanceDB::getInstanceDB();
        $sql = $db->prepare("DELETE FROM " . LotMetaData::getTableName() . " WHERE postId = %d", $postId);
        $db->query($sql);
    }

    public function clear_h2_from_navigation($template, $class) {
        unset($template);
        unset($class);
        return '<nav class="navigation %1$s" role="navigation"><div class="nav-links">%3$s</div></nav>';
    }

    public static function sort_meta_key($params = array()) {
        if (empty($params)) {
            $params = $_GET;
        }

        $approvedFields = Lot::$approvedFieldsBS;
        $metaKey = Lot::$orderFieldBS;

        if (!empty($params[Lot::NAME_PARAM]) && strrpos($params[Lot::NAME_PARAM], "lotIndex") === false) {
            $params = explode('|', $params[Lot::NAME_PARAM]);
            $metaKeyTmp = $params[0];
            if (in_array($metaKeyTmp, $approvedFields) !== false) {
                $metaKey = array($metaKeyTmp);
            }
        }

        return apply_filters('auctionforge_sort_meta_key', $metaKey[0]);
    }

    public static function sort_order($params = array()) {
        if (empty($params)) {
            $params = $_GET;
        }

        return self::sortOrderBSMeta($params);
    }

    private static function sortOrderBSMeta($params)
    {
        $orderBy = Lot::VALUE_NUM_BS;
        if (!empty($params[Lot::NAME_PARAM]) && strrpos($params[Lot::NAME_PARAM], "lotIndex") === false) {
            $params = explode('|', $params[Lot::NAME_PARAM]);
            $orderBy = $params[0];
            $order = $params[1];
        } else {
            $order = 'ASC';
        }
        $orderBy = preg_replace_callback('/\_\w/', function ($matches) {
            $matches = preg_replace("/\_/", "", $matches);
            return strtoupper($matches[0]);
        }, $orderBy);

        return array(
            'orderBy' => $orderBy,
            'order' => $order
        );
    }

    private static function sortOrderWPMeta($params)
    {
        if (!empty($params[Lot::NAME_PARAM]) && strrpos($params[Lot::NAME_PARAM], "lot_lotIndex") === false) {
            $params = explode('|', $params[Lot::NAME_PARAM]);
            $order = $params[1];
        } else {
            $order = 'ASC';
        }
        return array(
            'orderBy' => Lot::VALUE_NUM,
            'order' => $order
        );
    }

    /**
     * @param WP_Query $query
     */
    public function search_filter($query) {
        $bpData = $query->get(LotMetaData::BP_QUERY);
        
        // Always restrict search to lot post type and exclude unpublished auctions
        if (!is_admin() && $query->is_main_query() && $query->is_search) {
            $query->set('post_type', BidspiritLots::POST_TYPE);
            
            // Get all auction term IDs that should NOT be shown (ARCHIVED, READY, etc.)
            global $wpdb;
            $excludeStates = array('PENDING', 'PAUSED');
            $placeholders = implode(',', array_fill(0, count($excludeStates), '%s'));
            $excludeAuctionIds = $wpdb->get_col($wpdb->prepare(
                "SELECT term_id FROM {$wpdb->termmeta} 
                WHERE meta_key = 'auction_state' 
                AND meta_value IN ($placeholders)",
                $excludeStates
            ));
            
            // Also get hidden and shop auctions from settings
            $hiddenAuctions = SettingsHelper::getAuctionListFromSettings('hidden_auction');
            $shopAuctions = SettingsHelper::getAuctionListFromSettings('shop_auction');
            $excludeAuctionIds = array_merge($excludeAuctionIds, $hiddenAuctions, $shopAuctions);
            $excludeAuctionIds = array_filter($excludeAuctionIds);
            
            if (!empty($excludeAuctionIds)) {
                $tax_query = array(
                    array(
                        'taxonomy' => BidspiritLots::TAX_AUCTION_TYPE,
                        'field' => 'term_id',
                        'terms' => $excludeAuctionIds,
                        'operator' => 'NOT IN'
                    ),
                );
                $query->set('tax_query', $tax_query);
            }
            
            // Filter by auction time period (upcoming or past) - defaults to upcoming
            $auctionTime = !empty($_GET['auction_time']) ? sanitize_text_field($_GET['auction_time']) : 'upcoming';
            {
                if ($auctionTime === 'upcoming') {
                    $includeStates = array('READY', 'RUNNING');
                } elseif ($auctionTime === 'past') {
                    $includeStates = array('ENDED', 'ARCHIVED');
                } else {
                    $includeStates = null;
                }
                
                if ($includeStates) {
                    $placeholders2 = implode(',', array_fill(0, count($includeStates), '%s'));
                    $includeAuctionIds = $wpdb->get_col($wpdb->prepare(
                        "SELECT term_id FROM {$wpdb->termmeta} 
                        WHERE meta_key = 'auction_state' 
                        AND meta_value IN ($placeholders2)",
                        $includeStates
                    ));
                    
                    if (!empty($includeAuctionIds)) {
                        $existing_tax = $query->get('tax_query') ?: array();
                        $existing_tax[] = array(
                            'taxonomy' => BidspiritLots::TAX_AUCTION_TYPE,
                            'field' => 'term_id',
                            'terms' => $includeAuctionIds,
                            'operator' => 'IN'
                        );
                        if (count($existing_tax) > 1) {
                            $existing_tax['relation'] = 'AND';
                        }
                        $query->set('tax_query', $existing_tax);
                    } else {
                        // No auctions match the requested state — force empty results
                        $existing_tax = $query->get('tax_query') ?: array();
                        $existing_tax[] = array(
                            'taxonomy' => BidspiritLots::TAX_AUCTION_TYPE,
                            'field' => 'term_id',
                            'terms' => array(0),
                            'operator' => 'IN'
                        );
                        $query->set('tax_query', $existing_tax);
                    }
                }
            }
            
            // Increase posts per page for search to show more results
            $query->set('posts_per_page', 48);
        }
        
        if (!empty($_GET['taxonomy'])) {
            $taxonomy = sanitize_text_field($_GET['taxonomy']);
            if (!is_admin() && $query->is_main_query() && $query->is_search) {
                $tax_query = array(
                    array(
                        'taxonomy' => BidspiritLots::TAX_AUCTION_TYPE,
                        'field' => 'id',
                        'terms' => array(intval($taxonomy)),
                        'operator'  => 'IN'
                    ),
                );

                $query->set('tax_query', $tax_query);
                $query->set('post_type', BidspiritLots::POST_TYPE);
            }
        }

        if (!is_admin() && $query->is_main_query()) {
            // Start a session only if this request needs one (filter/search/paging,
            // returning visitor, or logged in) so plain views stay cacheable.
            $this->maybe_start_session();
            $should_reset_page = false;

            if (!empty($_GET[Lot::NAME_PARAM_CATEGORY])) {
                $rawCategory = $_GET[Lot::NAME_PARAM_CATEGORY];
                $categoryIds = array_filter(array_map('intval', explode(',', $rawCategory)));
                if (count($categoryIds) === 1) {
                    $filterCategory = $categoryIds[0];
                    $data["bp_field"][] = [
                        "field" => "categoryId",
                        "value" => $filterCategory,
                        "compare" => '='
                    ];
                } elseif (count($categoryIds) > 1) {
                    $filterCategory = implode(',', $categoryIds);
                    $data["bp_field"][] = [
                        "field" => "categoryId",
                        "value" => '(' . $filterCategory . ')',
                        "compare" => 'IN'
                    ];
                }
                $query->set(LotMetaData::BP_QUERY, array_merge($bpData, $data));

                if (!isset($_SESSION[self::PARAM_CATEGORY_BY]) || $rawCategory != $_SESSION[self::PARAM_CATEGORY_BY]) {
                    $should_reset_page = true;
                }
                $_SESSION[self::PARAM_CATEGORY_BY] = $rawCategory;
            } else {
                if (isset($_SESSION[self::PARAM_CATEGORY_BY]) && $_SESSION[self::PARAM_CATEGORY_BY] !== null) {
                    $should_reset_page = true;
                }
                $_SESSION[self::PARAM_CATEGORY_BY] = null;
            }

            if (!empty($_GET[Lot::NAME_PARAM_IS_SOLD])) {
                $isSold = esc_sql($_GET[Lot::NAME_PARAM_IS_SOLD]);

                if ($isSold == 'sold') {
                    $compare = ">";
                } else {
                    $compare = "=";
                }

                $data["bp_field"][] = [
                    "field" => "soldBid",
                    "value" => 0,
                    "compare" => $compare
                ];
                $query->set(LotMetaData::BP_QUERY, array_merge($bpData, $data));
            }

            if (!empty($_GET[Lot::NAME_PARAM_PHRASE])) {
                $searchPhrase = $_GET[Lot::NAME_PARAM_PHRASE];
                $query->set('s', $searchPhrase);

                if (!isset($_SESSION[self::PARAM_S]) || $searchPhrase != $_SESSION[self::PARAM_S]) {
                    $should_reset_page = true;
                }
                $_SESSION[self::PARAM_S] = $searchPhrase;
            } else {
                if (isset($_SESSION[self::PARAM_S]) && $_SESSION[self::PARAM_S] !== "") {
                    $should_reset_page = true;
                }
                $_SESSION[self::PARAM_S] = "";
            }

            if (!empty($_GET[Lot::NAME_PARAM_PER_PAGE])) {
                $perPage = $_GET[Lot::NAME_PARAM_PER_PAGE];
                if (!isset($_SESSION[self::PARAM_PER_PAGE]) || $perPage != $_SESSION[self::PARAM_PER_PAGE]) {
                    $should_reset_page = true;
                }
                $_SESSION[self::PARAM_PER_PAGE] = $perPage;
            }

            if ($should_reset_page) {
                if ($should_reset_page && get_query_var('paged') > 1) {
                    $query->set('paged', 1);
                    $_SESSION['auctionforge_reset_pagination'] = true;
                }
            }
            session_write_close();
        }
    }

    /**
     * Processing of empty filtering results
     * @param WP_Query $query
     */
    public function handle_empty_filter_results($query) {
        if (!is_admin() && $query->is_main_query() && $query->is_tax(self::TAX_AUCTION_TYPE)) {
            add_filter('posts_results', function($posts) use ($query) {
                if (empty($posts)) {
                    $query->is_404 = false;
                    $query->is_archive = true;
                    $query->is_tax = true;
                    status_header(200);
                }
                return $posts;
            }, 10, 1);
        }
    }

    /**
     * Redirect with excess pagination
     */
    public function redirect_excess_pagination() {
        if (is_tax(self::TAX_AUCTION_TYPE) && !is_404()) {
            global $wp_query;

            $paged = get_query_var('paged') ? absint(get_query_var('paged')) : 1;
            $max_pages = $wp_query->max_num_pages;

            if (defined(WP_DEBUG) && WP_DEBUG) {
                Debug::logData(sprintf(
                    'Pagination Debug - Current page: %d, Max pages: %d, Posts found: %d',
                    $paged,
                    $max_pages,
                    $wp_query->found_posts
                ));
            }

            if ($paged > $max_pages && $max_pages > 0) {
                $current_url = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
                $base_url = preg_replace('/page\/\d+\//', '', $current_url);

                $query_args = $_GET;
                if (!empty($query_args)) {
                    $redirect_url = add_query_arg($query_args, $base_url);
                } else {
                    $redirect_url = $base_url;
                }

                $redirect_url = str_replace('|', '%7C', $redirect_url);
                wp_safe_redirect($redirect_url);
                exit;
            }
        }
    }

    public function maybe_redirect_to_first_page() {
        if (!empty($_SESSION['auctionforge_reset_pagination'])) {
            // Reopen session briefly to clear the reset flag
            if (session_status() !== PHP_SESSION_ACTIVE) {
                @session_start();
            }
            unset($_SESSION['auctionforge_reset_pagination']);
            session_write_close();
            $current_url = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
            $base_url = preg_replace('/page\\/\\d+\\//', '', $current_url);
            $query_args = $_GET;
            if (!empty($query_args)) {
                $redirect_url = add_query_arg($query_args, $base_url);
            } else {
                $redirect_url = $base_url;
            }

            if (defined(WP_DEBUG) && WP_DEBUG) {
                Debug::logData('Redirecting 2 to: ' . $redirect_url);
            }

            $redirect_url = str_replace('|', '%7C', $redirect_url);

            wp_safe_redirect($redirect_url);
            exit;
        }
    }

    /**
     * @param WP_Query $query
     */
    public function bidspirit_lot_per_page($query)
    {
        if (!Conditions::isMainQuery($query)) {
            return;
        }

        // Start a session only if this request needs one so plain views stay cacheable.
        $this->maybe_start_session();

        if (!empty($_GET[Lot::NAME_PARAM_PER_PAGE])) {
            if (!isset($_SESSION[self::PARAM_PER_PAGE]) || is_null($_SESSION[self::PARAM_PER_PAGE])) {
                $_SESSION[self::PARAM_PER_PAGE] = get_option('posts_per_page', 10);
            }

            $perPage = $_GET[Lot::NAME_PARAM_PER_PAGE];
            $query->set('posts_per_page', $perPage);

            if ($perPage != $_SESSION[self::PARAM_PER_PAGE]) {
                $query->set(self::PARAM_PAGED, 1);
            }

            $_SESSION[self::PARAM_PER_PAGE] = $perPage;
        }

        // Only touch session state when a session is actually active — plain
        // anonymous views skip the session (to stay cacheable), so reading
        // $_SESSION here would otherwise emit an "undefined key" warning.
        if (session_status() === PHP_SESSION_ACTIVE) {
            if (!isset($_SESSION[self::PARAM_PER_PAGE]) || is_null($_SESSION[self::PARAM_PER_PAGE])) {
                $_SESSION[self::PARAM_PER_PAGE] = get_option('posts_per_page', 10);
            }
            session_write_close();
        }
    }

    public function bidspirit_lot_solds($query)
    {
        if (Conditions::isAuctionPage($query)) {
            if (SettingsHelper::isChecked(Settings::HIDE_UNSOLD_ITEMS, false)) {
                $auction = get_queried_object();
                if (!($auction instanceof WP_Term)) {
                    return $query;
                }

                $auctionState = SettingsHelper::getTermOption($auction->term_id, 'auction_state');
                $isArchived = Auction::isAuctionArchived($auctionState);

                if ($isArchived) {
                    $bpQuery = $query->get('bp_query');
                    if (empty($bpQuery)) {
                        $bpQuery = [
                            "bp_field" => [
                                [
                                    "field" => "soldBid",
                                    "value" => 1,
                                    "compare" => '>'
                                ]
                            ]
                        ];
                    } else {
                        $bpQuery["bp_field"][] = array(
                            "field" => "soldBid",
                            "value" => 1,
                            "compare" => '>'
                        );
                    }

                    $query->set('bp_query', $bpQuery);
                }
            }
        }
        return $query;
    }

    /**
     * Keep bp_meta_data.leadingBid/soldBid current for OPEN auctions so the
     * bid-dependent sorts (Leading Bid / Price / Most Active) reflect live bids.
     * The lot cards fetch live bids for DISPLAY, but the sort reads the synced
     * meta table, which otherwise stays at 0 for pre-bids — so "lots with bids
     * first" could never group correctly. Throttled to one API call per auction
     * per 90s; only the lots that actually have bids/sales are written.
     *
     * @param WP_Query $query
     */
    public function refresh_leading_bids_for_sort($query)
    {
        if (is_admin() || !$query->is_main_query() || !Conditions::isAuctionPage($query)) {
            return;
        }

        // Only needed when sorting by a bid-dependent field.
        $sortBy = isset($_GET['sort_by']) ? (string) $_GET['sort_by'] : '';
        $sortField = $sortBy !== '' ? explode('|', $sortBy)[0] : '';
        if (!in_array($sortField, array('leadingBid', 'effectivePrice', 'mostActive'), true)) {
            return;
        }

        $auction = get_queried_object();
        if (!($auction instanceof WP_Term)) {
            return;
        }
        $termId = $auction->term_id;

        // Ended/archived auctions already hold final results in the meta table.
        if (Auction::isAuctionArchived(SettingsHelper::getTermOption($termId, 'auction_state'))) {
            return;
        }

        $bsId = SettingsHelper::getTermOption($termId, 'auction_id');
        if (empty($bsId)) {
            return;
        }

        // Throttle: at most one refresh per auction per 90 seconds.
        $throttleKey = 'af_sort_bids_' . $bsId;
        if (get_transient($throttleKey)) {
            return;
        }
        set_transient($throttleKey, 1, 90);

        $response = BidSpiritRequest::send('items/getAllItemsInfoForAuction.api', array('auctionId' => $bsId, 'language' => 'en'));
        if (empty($response['response'])) {
            return;
        }
        $decoded = json_decode($response['response']);
        if (!isset($decoded->response->itemsInfo)) {
            return;
        }

        global $wpdb;
        $table = $wpdb->prefix . LotMetaData::TABLE_LOT_META;
        foreach ($decoded->response->itemsInfo as $idx => $info) {
            $leadingBid = (!empty($info->leadingBid) && isset($info->leadingBid->price)) ? floatval($info->leadingBid->price) : 0;
            $soldBid = (!empty($info->soldBid) && isset($info->soldBid->price)) ? floatval($info->soldBid->price) : 0;
            if ($leadingBid <= 0 && $soldBid <= 0) {
                continue; // no activity — leave the synced 0
            }
            $itemIndex = isset($info->itemIndex) ? $info->itemIndex : $idx;
            $wpdb->update(
                $table,
                array('leadingBid' => $leadingBid, 'soldBid' => $soldBid),
                array('auctionId' => $bsId, 'itemIndex' => $itemIndex)
            );
        }
    }

    public function polylang_lang()
    {
        /** @var WP_Post $post */
        global $post;

        $mlSupport = new MultiLanguageSupport();
        if (PolylangSupport::isFullSupport() && $mlSupport->isLotSupport()) {
            return;
        }

        if (PolylangSupport::isPolylangActive() && is_single() && $post->post_type == BidspiritLots::POST_TYPE) {
            if (!empty($_GET['bs-lang'])) {
                pll_set_post_language($post->ID, $_GET['bs-lang']);
            } else {
                pll_set_post_language($post->ID, pll_default_language());
            }
        }
    }

    /**
     * @param $post_link string
     * @param $post WP_Post
     * @param $leavename boolean
     * @param $sample boolean
     * @return string
     */
    function polylang_link($post_link, $post, $leavename, $sample) {
        unset($leavename);
        unset($sample);
        if (PolylangSupport::isPolylangActive() && $post->post_type == BidspiritLots::POST_TYPE) {
            $post_link = LotHelper::getLotLink($post_link);
        }
        return $post_link;
    }

    function polylang_term_link($termlink, $term, $taxonomy) {
        unset($term);
        if (PolylangSupport::isPolylangActive() && $taxonomy == self::TAX_AUCTION_TYPE) {
            $defaultLang = MultiLanguageSupport::getDefaultLangCode();
            $lang = MultiLanguageSupport::getDefaultLangCode();

            if ($lang != $defaultLang) {
                $termlink = LotHelper::getLotLink($termlink, $defaultLang);
            }
        }

        return $termlink;
    }

    /**
     * Register new types of posts and taxonomies in WordPress
     * @return void
     */
    public function create_post_type__lot()
    {
        register_taxonomy(self::TAX_TAGS_TYPE, array(self::POST_TYPE), array(
            self::LABELS => array(
                'name' => __('Category'),
                'singular_name' => __('Category'),
                'search_items' => __('Search Categories'),
                'popular_items' => __('Popular Categories'),
                'all_items' => __('All Categories'),
                'parent_item' => __('Parent Category'),
                'parent_item_colon' => __('Parent Category'),
                'edit_item' => __('Edit Category'),
                'update_item' => __('Update Category'),
                'add_new_item' => __('Add New Category'),
                'new_item_name' => __('New Category'),
                'separate_items_with_commas' => __('Separate categories with commas'),
                'add_or_remove_items' => __('Add or remove category'),
                'choose_from_most_used' => __('Choose from the most used category'),
                'menu_name' => __('Categories'),
            ),
            self::DESCRIPTION => 'Tags of Auctions',
            'public' => true,
            'show_in_nav_menus' => false,
            'show_ui' => true,
            'show_tagcloud' => false,
            'update_count_callback' => '_update_post_term_count',
            'hierarchical' => false,
            'rewrite' => array(
                'slug' => 'auction-tag',
                'hierarchical' => false,
                'with_front' => true,
                'feed' => false
            ),
            'show_admin_column' => true,
            'query_var' => true,
        ));

        register_taxonomy(
            self::TAX_AUCTION_TYPE,
            self::POST_TYPE,
            array(
                self::LABELS => array(
                    'name' => _x('Auctions', 'auctionforge'),
                    'menu_name' => __('Auctions', 'auctionforge'),
                    'singular_name' => _x('Auction', 'auctionforge'),
                    'search_items' => __('Search Auctions', 'auctionforge'),
                    'popular_items' => __('Popular Auctions', 'auctionforge'),
                    'all_items' => __('All Auctions', 'auctionforge'),
                    'parent_item' => __('Parent Auction', 'auctionforge'),
                    'parent_item_colon' => __('Parent Auction', 'auctionforge'),
                    'edit_item' => __('Edit Auction', 'auctionforge'),
                    'update_item' => __('Update Auction', 'auctionforge'),
                    'add_new_item' => __('Add New Auction', 'auctionforge'),
                    'new_item_name' => __('New Sale Number', 'auctionforge'),
                    'separate_items_with_commas' => __('Separate auctions with commas', 'auctionforge'),
                    'add_or_remove_items' => __('Add or remove auctions', 'auctionforge'),
                    'choose_from_most_used' => __('Choose from the most used auctions', 'auctionforge'),
                ),
                'rewrite' => array(
                    'slug' => 'auction',
                    'with_front' => true,
                    'pages' => false,
                    'feeds' => false,
                    'feed' => false
                ),
                'public' => true,
                'show_in_nav_menus' => true,
                'show_ui' => true,
                'show_tagcloud' => false,
                'update_count_callback' => '_update_post_term_count',
                'hierarchical' => true,
                'show_admin_column' => true,
                'query_var' => true,
            )
        );

        register_post_type(self::POST_TYPE, array(
            self::LABEL => __('Lot', 'auctionforge'),
            self::DESCRIPTION=> __('All lots from all auctions', 'auctionforge'),
            self::LABELS => array(
                'name' => _x('Lots', 'Post Type General Name', 'auctionforge'),
                'singular_name' => _x('Lot', 'Post Type Singular Name', 'auctionforge'),
                'menu_name' => __('Bidspirit', 'auctionforge'),
                'parent_item_colon' => __('Parent Lot', 'auctionforge'),
                'all_items' => __('Lots', 'auctionforge'),
                'view_item' => __('View Lot', 'auctionforge'),
                'add_new_item' => __('Add New Lot', 'auctionforge'),
                'add_new' => __('Add New', 'auctionforge'),
                'edit_item' => __('Edit Lot', 'auctionforge'),
                'update_item' => __('Update Lot', 'auctionforge'),
                'search_items' => __('Search Lot', 'auctionforge'),
                'not_found' => __('Not Found', 'auctionforge'),
                'not_found_in_trash' => __('Not found in Trash', 'auctionforge'),
            ),
            'supports' => array('title', 'editor', 'thumbnail', 'custom-fields',),
            'taxonomies' => array(self::TAX_AUCTION_TYPE),
            'public' => true,
            'show_ui' => true,
            'show_in_menu' => true,
            'show_in_nav_menus' => true,
            'show_in_admin_bar' => true,
            'menu_position' => 5,
            'can_export' => true,
            'hierarchical' => false,
            'rewrite' => array(
                'slug' => 'auction/%auction_number%',
                'with_front' => true,
                'pages' => false,
                'feeds' => false,
                'feed' => false
            ),
            'has_archive' => self::TAX_AUCTION_TYPE,
            'query_var' => true,
            'exclude_from_search' => false,
            'publicly_queryable' => true,
            'capability_type' => 'post',
        ));
    }

    /**
     * Formation and display of additional meta fields for auctions
     * @param $term WP_Term
     */
    public function bidspirit_taxonomy_edit_custom_meta_field($term) {
        $term_meta = array();
        $inputs = array_merge($this->getFields(), $this->getCheckboxFields());
        foreach ($inputs as $field) {
            $term_meta[$field] = get_term_meta($term->term_id, $field);
        }

        $inputs = array(
            'id' => array(
                self::LABEL => __('Bidspirit ID', 'auctionforge'),
                self::DESCRIPTION => '',
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'id']) ? esc_attr($term_meta[self::PREFIX_FIELD . 'id'][0]) : '',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => self::LABEL_DISABLED
            ),
            'pdf' => array(
                self::LABEL => __('Hidden pdf file link', 'auctionforge'),
                self::DESCRIPTION => __('Hidden link of pdf file on auction', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'pdf']) ? esc_attr($term_meta[self::PREFIX_FIELD . 'pdf'][0]) : '',
                self::TYPE => self::TYPE_FIELD_CHECKBOX,
                self::LABEL_CLASS => ''
            ),
            'bg' => array(
                self::LABEL => __('Background', 'auctionforge'),
                self::DESCRIPTION => __('Background for lots. Default value (#ffffff)', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'bg']) ? esc_attr($term_meta[self::PREFIX_FIELD . 'bg'][0]) : '',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => ''
            ),
            'number' => array(
                self::LABEL => __('Number', 'auctionforge'),
                self::DESCRIPTION => __('Number auction', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'number']) ? esc_attr($term_meta[self::PREFIX_FIELD . 'number'][0]) : '',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => ''
            ),
            'name' => array(
                self::LABEL => __('Name', 'auctionforge'),
                self::DESCRIPTION => __('Name auction', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'name']) ? esc_attr($term_meta[self::PREFIX_FIELD . 'name'][0]) : '',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => ''
            ),
            'days' => array(
                self::LABEL => __('Days', 'auctionforge'),
                self::DESCRIPTION => __('Auction Days', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'days']) ? esc_attr(json_encode($term_meta[self::PREFIX_FIELD . 'days'][0])) : '',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => self::LABEL_DISABLED
            ),
            'docs' => array(
                self::LABEL => __('Docs', 'auctionforge'),
                self::DESCRIPTION => __('Auction Docs', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'docs']) ? esc_attr(json_encode($term_meta[self::PREFIX_FIELD . 'docs'][0])) : '',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => self::LABEL_DISABLED
            ),
            'address' => array(
                self::LABEL => __('Address', 'auctionforge'),
                self::DESCRIPTION => __('Location', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'address']) ? esc_attr($term_meta[self::PREFIX_FIELD . 'address'][0]) : '',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => ''
            ),
            'info' => array(
                self::LABEL => __('Info', 'auctionforge'),
                self::DESCRIPTION => __('Info', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'info']) ? esc_attr($term_meta[self::PREFIX_FIELD . 'info'][0]) : '',
                self::TYPE => self::TYPE_FIELD_TEXTAREA,
                self::LABEL_CLASS => ''
            ),
            'commission' => array(
                self::LABEL => __('Commission', 'auctionforge'),
                self::DESCRIPTION => __('Commission info', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'commission']) ? esc_attr($term_meta[self::PREFIX_FIELD . 'commission'][0]) : '',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => ''
            ),
            'state' => array(
                self::LABEL => __('State', 'auctionforge'),
                self::DESCRIPTION => __('State', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'state']) ? esc_attr($term_meta[self::PREFIX_FIELD . 'state'][0]) : '',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => self::LABEL_DISABLED
            ),
            'displayStartPriceInCatalog' => array(
                self::LABEL => __('displayStartPriceInCatalog', 'auctionforge'),
                self::DESCRIPTION => __('displayStartPriceInCatalog', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'displayStartPriceInCatalog']) ? esc_attr
                ($term_meta[self::PREFIX_FIELD . 'displayStartPriceInCatalog'][0]) : 'false',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => self::LABEL_DISABLED
            ),
            'showEstimatedPriceInItemsList' => array(
                self::LABEL => __('showEstimatedPriceInItemsList', 'auctionforge'),
                self::DESCRIPTION => __('showEstimatedPriceInItemsList', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'showEstimatedPriceInItemsList']) ? esc_attr
                ($term_meta[self::PREFIX_FIELD . 'showEstimatedPriceInItemsList'][0]) : 'false',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => self::LABEL_DISABLED
            ),
            'lastCatalogUpdate' => array(
                self::LABEL => __('Last auction update', 'auctionforge'),
                self::DESCRIPTION => __('lastCatalogUpdate', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'lastCatalogUpdate']) ? esc_attr
                ($term_meta[self::PREFIX_FIELD . 'lastCatalogUpdate'][0]) : 'false',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => self::LABEL_DISABLED
            ),
            'automaticAuction' => array(
                self::LABEL => __('Automatic auction', 'auctionforge'),
                self::DESCRIPTION => __('automaticAuction', 'auctionforge'),
                self::VALUE => !empty($term_meta[self::PREFIX_FIELD . 'automaticAuction']) ? esc_attr
                ($term_meta[self::PREFIX_FIELD . 'automaticAuction'][0]) : 'true',
                self::TYPE => self::TYPE_FIELD_TEXT,
                self::LABEL_CLASS => self::LABEL_DISABLED
            ),
        );

        foreach ($inputs as $key => $field) {
            echo View::render('admin.view.fields.term_' . $field[self::TYPE], array(
                'key' => $key,
                'data' => $field,
            ));
        }
    }

    /**
     * Saving Fields for Taxonomy
     * @param $term_id string
     * @return void
     */
    public function bidspirit_save_taxonomy_custom_meta_field( $term_id ) {
        $excludeProp = array(
            self::PREFIX_FIELD . 'days',
            self::PREFIX_FIELD . 'docs'
        );
        if ( isset( $_POST['term_meta'] ) ) {
            $cat_keys = array_keys($_POST['term_meta']);

            $cat_keys = array_merge($cat_keys, $this->getCheckboxFields());

            foreach ( $cat_keys as $key ) {
                if (empty($_POST['term_meta'][$key]) && in_array($key, $this->getCheckboxFields())) {
                    $_POST['term_meta'][$key] = 'off';
                }

                if (isset($_POST['term_meta'][$key]) && !in_array($key, $excludeProp)) {
                    $value = addslashes($_POST['term_meta'][$key]);
                    update_term_meta($term_id, $key, $value);
                }
            }
        }
    }

    /**
     * Fix for filter polylang/include/crud-posts.php add_action('save_post_lot', array($this, 'set_post_parent'), 10, 3);
     * @param $post_parent int
     * @param $post_ID int
     * @param $new_postarr array
     * @param $postarr array
     * @return int
     */
    public function set_post_parent($post_parent, $post_ID, $new_postarr, $postarr)
    {
        if ($new_postarr['post_type'] == BidspiritLots::POST_TYPE && isset($postarr['meta_input']['lot_id'])) {
            $lotId = $postarr['meta_input']['lot_id'];
            return $lotId;
        }
        return $post_parent;
    }

    public function bp_insert_post_data($data, $postarr, $unsanitized_postarr)
    {
        if (!is_admin() && isset($data['post_content']) && $data['post_type'] == BidspiritLots::POST_TYPE) {
            $data['post_content'] = sanitize_post($unsanitized_postarr['post_content'], "raw");
        }
        return $data;
    }

    /**
     * Linking the type of lot posts with created taxonomies
     * @return void
     */
    public function post_tag_for_pages()
    {
        register_taxonomy_for_object_type(self::TAX_AUCTION_TYPE, self::POST_TYPE);
        register_taxonomy_for_object_type(self::TAX_TAGS_TYPE, self::POST_TYPE);
    }

    /**
     * Formation of SEF links for auctions
     * @param $permalink
     * @param $post
     * @return string|string[]
     */
    public function auction_permalink($permalink, $post)
    {
        if (strpos($permalink, '%auction_number%') === false) {
            return $permalink;
        }

        $terms = get_the_terms($post, self::TAX_AUCTION_TYPE);
        if (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) {
            $term_slug = array_pop($terms)->slug;
        } else {
            $term_slug = 'no-auction_number';
        }

        return str_replace('%auction_number%', $term_slug, $permalink);
    }

    /**
     * Sorting fields for lots in the admin part of the lot list site
     * @param $columns
     * @return array
     */
    public function lot_filter_columns($columns)
    {
        $newColumns = array();
        $columns[self::LABEL_PRICE] = __('Price', 'auctionforge');
        $columns['updated'] = __('Updated', 'auctionforge');

        $newColumns['cb'] = $columns['cb'];
        $newColumns['title'] = $columns['title'];
        $newColumns[self::LABEL_PRICE] = $columns[self::LABEL_PRICE];
        $newColumns['taxonomy-auction_number'] = $columns['taxonomy-auction_number'];
        $newColumns['taxonomy-auction_tag'] = $columns['taxonomy-auction_tag'];
        $newColumns['date'] = $columns['date'];
        return $newColumns;
    }

    /**
     * Lot price display in the admin part of the lot list site
     * @param $column
     * @param $post_id
     * @return void
     */
    public function lot_realestate_column($column, $post_id)
    {
        if ( self::LABEL_PRICE === $column ) {
            $price = get_post_custom_values('lot_start_price', $post_id);
            if (!empty($price)) {
                echo (int)$price[0];
            }
        }
    }

    /**
     * Add sorting the list of lots by price
     * @param $columns
     * @return string
     */
    public function bidspirit_lot_sortable_columns($columns)
    {
        $columns[self::LABEL_PRICE] = 'lot_start_price';
        return $columns;
    }

    /**
     * Formation of a request for sorting by price
     * @param $query
     */
    public function bidspirit_lot_orderby($query)
    {
        if (!is_admin() || !$query->is_main_query()) {
            return;
        }

        if ('lot_start_price' === $query->get('orderby')) {
            $query->set('orderby', 'meta_value');
            $query->set('meta_key', 'lot_start_price');
            $query->set('meta_type', 'numeric');
        }
    }

    /**
     * @param $title string
     * @param $auction WP_Term
     * @return string
     */
    public function auction_title_build($title, $auction)
    {
        $auctionName = SettingsHelper::getTermOption($auction->term_id, 'auction_name');
        $auctionNumber = SettingsHelper::getTermOption($auction->term_id, 'auction_number');
        if ($auctionName !== "") {
            $title = $auctionName;
        } else if (!empty($auctionNumber)) {
            $title = __('Auction', 'auctionforge') . " " . $auctionNumber;
        }

        return $title;
    }

    public function fix_auction_seo_title($title)
    {
        if (is_tax('auction_number') && is_archive()) {
            /** @var WP_Term $auction */
            $auction = get_queried_object();
            if (!empty($title['title']) && sanitize_title($title['title']) == sanitize_title($auction->name)) {
                $auctionName = SettingsHelper::getTermOption($auction->term_id, 'auction_name');
                if ($auctionName == '') {
                    return $title;
                }
                $title['title'] = $auctionName;
            }
        }
        return $title;
    }

    public function insert_image_opengraph()
    {
        global $post;
        if (is_single() && $post->post_type == BidspiritLots::POST_TYPE) {
            $featureImage = LotHelper::getFeatureImageByID($post->ID);
            echo "<meta property=\"og:image\" content=\"" . $featureImage . "\"/>\r\n";
        }

        if (is_archive() && is_tax('auction_number')) {
            $auction = get_queried_object();
            $auctionDays = SettingsHelper::getTermOption($auction->term_id, 'auction_days');
            $auctionDays = \auctionforge\inc\controllers\CoverImageOverride::applyToDays($auctionDays, $auction->term_id);
            $part = get_query_var('part');
            if (!empty($part) && !empty($auctionDays[intval($part) - 1])) {
                $auctionDay = $auctionDays[intval($part) - 1];
            } else {
                //$auctionDay = null;
                //$query->set_404();
                //status_header(404);
                $auctionDay = $auctionDays[0];
            }
            if (!empty($auctionDay->image)) {
                $featureImage = $auctionDay->image;
            } else {
                $featureImage = LotHelper::getPlaceholderImage();
            }
            echo "<meta property=\"og:image\" content=\"" . $featureImage . "\"/>\r\n";
        }
    }

    public function showcase_action($lotIndex, $dateTime)
    {
        if (is_plugin_active('woocommerce/woocommerce.php') && SettingsHelper::getOption('showcase_enable', false, 'file')) {
            $productId = wc_get_product_id_by_sku($lotIndex);
            $product = wc_get_product($productId);
            $price = $product->get_price_html();
            echo View::render('templates.parts.chunks.showcase', [
                'price' => $price
            ]);
        }
    }

    /**
     * @return array
     */
    public function getFields()
    {
        return $this->fields;
    }

    /**
     * @return void
     */
    public function setFields()
    {
        $this->fields = array(
            self::PREFIX_FIELD . 'id',
            self::PREFIX_FIELD . 'bg',
            self::PREFIX_FIELD . 'name',
            self::PREFIX_FIELD . 'days',
            self::PREFIX_FIELD . 'number',
            self::PREFIX_FIELD . 'address',
            self::PREFIX_FIELD . 'info',
            self::PREFIX_FIELD . 'commission',
            self::PREFIX_FIELD . 'docs',
            self::PREFIX_FIELD . 'state',
            self::PREFIX_FIELD . 'displayStartPriceInCatalog',
            self::PREFIX_FIELD . 'showEstimatedPriceInItemsList',
            self::PREFIX_FIELD . 'lastCatalogUpdate',
            self::PREFIX_FIELD . 'automaticAuction',
        );
    }

    /**
     * @return array
     */
    public function getCheckboxFields()
    {
        return $this->checkboxField;
    }

    /**
     * @return void
     */
    public function setCheckboxFields()
    {
        $this->checkboxField = array(
            self::PREFIX_FIELD . 'pdf'
        );
    }
}

$bidspiritLots = new BidspiritLots();
$bidspiritLots->init();
