<?php

namespace auctionforge\inc\model;

use auctionforge\inc\abs\Model;
use auctionforge\inc\BidSpiritRequest;
use auctionforge\inc\controllers\BidspiritLots;
use auctionforge\inc\controllers\HummingbirdSupport;
use auctionforge\inc\controllers\MultiLanguageSupport;
use auctionforge\inc\controllers\PolylangSupport;
use auctionforge\inc\controllers\Settings;
use auctionforge\inc\Debug;
use auctionforge\inc\helpers\LotHelper;
use auctionforge\inc\helpers\SettingsHelper;
use auctionforge\inc\InstanceDB;
use auctionforge\inc\traits\LoggerInfo;
use WP_Post;
use WP_Term;

class Auction extends Model
{
    use LoggerInfo;

    const STATE_PENDING = "PENDING";
    const STATE_READY = "READY";
    const STATE_PRE_AUCTION = "PRE_AUCTION";
    const STATE_RUNNING = "RUNNING";
    const STATE_PAUSED = "PAUSED";
    const STATE_POST_AUCTION = "POST_AUCTION";
    const STATE_ENDING = "ENDED";
    const STATE_ARCHIVED = "ARCHIVED";
    const DATE_FORMAT = "Y-m-d H:i:s";
    const META_FIELD_TAGS = "_auction_tags";
    const TERM = 'auction_number';

    /**
     * Auction number
     * @var string
     */
    private $number;
    private $termId;

    private $address;
    private $days;
    private $docs;

    /**
     * Status auction
     * @var static
     */
    private $state;
    private $commission;
    private $commissionInfo;
    private $info;
    private $date;
    private $displayStartPriceInCatalog;
    private $showEstimatedPriceInItemsList;
    private $lastCatalogUpdate;
    private $automaticAuction;

    public static $pagingSettings = array(
        'show_all' => false,
        'end_size' => 1,
        'mid_size' => 2,
    );

    /**
     * Search for an auction in the database by its number
     * @param $number
     * @return array|object|void|null
     */
    public static function findAuctionByNumber($number)
    {
        return get_term_by('slug', sanitize_title($number), Auction::TERM);
    }

    /**
     * @param $id
     * @param $langCode
     * @return false|WP_Term
     */
    public static function findAuctionById($id, $langCode = false)
    {
        $args = array(
            'post_type'  => 'lot',
            'taxonomy' => Auction::TERM,
            'hide_empty' => false,
            'meta_query' => array(
                'relations' => 'AND',
                'id' => array(
                    'key' => 'auction_id',
                    'value' => $id
                )
            )
        );

        if ($langCode) {
            $args = array_merge($args, [
                'lang' => $langCode
            ]);
        }

        $terms = get_terms($args);

        if ($terms instanceof \WP_Error) {
            return false;
        }

        /**
         * Will fix trouble here
         */
        if (!empty($terms) && !empty($terms[0]) && $terms[0] instanceof WP_Term) {
            return $terms[0];
        } else {
            return false;
        }
    }

    /**
     * @param $id
     * @param $langCode
     * @return false|WP_Term
     */
    public static function findAuctionByIdWithLang($id, $langCode = false)
    {
        $args = array(
            'taxonomy' => Auction::TERM,
            'hide_empty' => false,
            'meta_query' => array(
                'relations' => 'AND',
                'id' => array(
                    'key' => 'auction_id',
                    'value' => $id
                )
            )
        );

        if ($langCode) {
            $args = array_merge($args, [
                'lang' => $langCode
            ]);
        }

        $terms = get_terms($args);
        if ($terms instanceof \WP_Error) {
            return false;
        }

        /*file_put_contents($_SERVER['DOCUMENT_ROOT'] . '/dump/var_dump-' . date("Y-m-d-H-i-s") . ":" . rand(1000, 9999) . '.txt',
            var_export(array(
                $terms,
                $args,
                ("File name: " . dirname(__FILE__) . "/" . basename(__FILE__) . ":" . __LINE__)
            ), true));*/

        /**
         * Will fix trouble here
         */
        if (!empty($terms) && !empty($terms[0]) && $terms[0] instanceof WP_Term) {
            return $terms[0];
        } else {
            return false;
        }
    }

    /**
     * Get Active auctions
     * @return WP_Term[]
     */
    public static function getActiveAuction($active = true, $isSyncQuery = true)
    {
        return self::getAuctions($active, $isSyncQuery);
    }

    public static function getTermFields($terms, $key)
    {
        $data = array();
        if (!empty($terms)) {
            foreach ($terms as $index => $term) {
                $term = (array)$term;
                if (preg_match("/auction_/", $key)) {
                    $data[$index] = SettingsHelper::getTermOption($term['term_id'], $key);
                } else {
                    if (!empty($term[$key])) {
                        $data[$index] = $term[$key];
                    }
                }
            }
        }
        return $data;
    }

    /**
     * Get Archive auctions
     * @return WP_Term[]
     */
    public static function getArchiveAuction($active = false, $isSyncQuery = true)
    {
        return self::getAuctions($active, $isSyncQuery);
    }

    /**
     * Get auctions
     * @deprecated Since v2.2.7.0 - Use `getAuctions2` instead.
     * @param bool $active
     * @return array
     */
    private static function getAuctions($active = true, $isSyncQuery = true)
    {
        $allowStatus = array('ARCHIVED', 'ENDED');
        if ($active) {
            $cond = 'NOT IN';
            $order = 'ASC';
        } else {
            $cond = 'IN';
            $order = 'DESC';
        }
        $args = array(
            'post_type'  => 'lot',
            BidspiritLots::LABEL_TAXONOMY => array(BidspiritLots::TAX_AUCTION_TYPE),
            'hide_empty' => 0,
            'meta_query' => array(
                'relation' => 'AND',
                array(
                    'key' => 'auction_state',
                    'value' => $allowStatus,
                    'compare' => $cond
                )
            ),
            'order' => $order,
            'orderby' => 'term_id'
        );
        if ($isSyncQuery) {
            return get_terms(apply_filters('auctionforge_query_auction_params_sync', $args));
        } else {
            return get_terms(apply_filters('auctionforge_query_auction_params', $args));
        }
    }

    public static function getAllAuctionsIds()
    {
        $mlSupport = new MultiLanguageSupport();

        $db = InstanceDB::getInstanceDB();
        $sql = "SELECT meta.meta_id, meta.term_id, meta.meta_value FROM " . $db->prefix . "termmeta AS meta";
        if ($mlSupport->isLotSupport()) {
            $sql .= " LEFT JOIN " . $db->prefix . "term_relationships AS rel ON meta.term_id = rel.object_id";
        }

        $sql .= " WHERE meta.meta_key = 'auction_id'";
        if ($mlSupport->isLotSupport()) {
            $termId = pll_default_language('tl_term_id');
            $sql .= " AND rel.term_taxonomy_id = " . $termId;
        }

        $qResult = $db->get_results($sql);
        $result = array();
        if (!empty($qResult)) {
            foreach ($qResult as $item) {
                $result[$item->meta_value] = $item;
            }
        }
        return $result;
    }

    private static function checkEmptyAuction($auctionId)
    {
        $response = BidSpiritRequest::send('users/initSession.api', [
            'auctionId' => $auctionId,
            'language' => MultiLanguageSupport::getDefaultLangCode()
        ]);
        $response = json_decode($response['response']);

        return empty((array)$response->response);
    }

    /**
     * @param $auctionId
     * @return bool
     */
    public static function isAuctionShop($auctionId)
    {
        $shopAuctions = SettingsHelper::getAuctionListFromSettings('shop_auction');
        return (in_array($auctionId, $shopAuctions));
    }

    /**
     * @param $auctionState
     * @return bool
     */
    public static function isAuctionArchived($auctionState)
    {
        $allowStatus = array(self::STATE_ARCHIVED, self::STATE_ENDING);
        return in_array($auctionState, $allowStatus);
    }

    /**
     * Find all posts by auction number
     * @param $auctionId
     * @param string[] $status
     * @return int[]|WP_Post[]
     */
    public static function getAllPosts($auctionId, $status = array(
        SettingsHelper::STATUS_PUBLISH,
        SettingsHelper::STATUS_DRAFT,
        SettingsHelper::STATUS_FUTURE
    )) {
        return get_posts(array(
            "numberposts" => -1,
            "post_status" => $status,
            LotMetaData::BP_QUERY => array(
                "bp_id" => array(1),
                "term_id" => intval($auctionId),
            ),
            "post_type" => "lot",
            "suppress_filters" => false
        ));
    }

    public static function getAllAuctionPostsBS($termId) {
        $db = InstanceDB::getInstanceDB();
        $sql = "SELECT `postId` FROM " . $db->prefix . LotMetaData::TABLE_LOT_META . " WHERE `termId` = %d";
        $sql = $db->prepare($sql, sanitize_title($termId));

        return $db->get_col($sql);
    }

    /**
     * Find an auction entry by actionIndex
     * @param $auctionSlug string
     * @return int
     */
    public static function searchAuction($auctionSlug) {
        $db = InstanceDB::getInstanceDB();
        $sql = "SELECT `term_id` FROM " . $db->terms . " WHERE slug = %s";
        $sql = $db->prepare($sql, sanitize_title($auctionSlug));
        $result = $db->get_col($sql);
        if (!empty($result)) {
            return $result[0];
        } else {
            return 0;
        }
    }

    public static function getAuctionInfo($auctionId, $lang)
    {
        $response = BidSpiritRequest::send("auctions/getAuctionInfo.api", [
            "auctionId" => intval($auctionId),
            "language" => $lang
        ]);

        if ($response['response']) {
            $response = json_decode($response['response']);

            if (!empty($response) && isset($response->response)) {
                return $response->response;
            }
        }
        return [];
    }

    public static function updateAuctionInfo($term, $auctionId, $lang)
    {
        if ($term instanceof \WP_Term) {
            $response = BidSpiritRequest::send("auctions/getAuctionInfo.api", [
                "auctionId" => intval($auctionId),
                "language" => $lang
            ]);
            $termId = $term->term_id;
            if ($response['response']) {
                $response = json_decode($response['response']);
                $auctionModel = new Auction();
                $auctionModel->loadAttributes($response->response);
                $auctionModel->updateOptionMeta($termId);
            }
        }
    }

    /**
     * Update meta fields for auction
     * @param $id_term
     * @return void
     */
    public function updateOptionMeta($id_term)
    {
        $isTermUpdate = false;
        $term_meta = array(
            'auction_id' => $this->getId(),
            'auction_name' => $this->getName(),
            'auction_days' => $this->getDays(),
            'auction_number' => $this->getNumber(),
            'auction_address' => $this->getAddress(),
            'auction_info' => $this->getInfo(),
            'auction_commission' => $this->getCommission(),
            'auction_commissionInfo' => $this->getCommissionInfo(),
            'auction_state' => $this->getState(),
            'auction_docs' => $this->getDocs(),
            'auction_date' => $this->getDate(),
            'auction_displayStartPriceInCatalog' => $this->getDisplayStartPriceInCatalog(),
            'auction_showEstimatedPriceInItemsList' => $this->getShowEstimatedPriceInItemsList(),
            'auction_lastCatalogUpdate' => $this->getLastCatalogUpdate(),
            'auction_automaticAuction' => Auction::toString($this->getAutomaticAuction()),
        );

        $term_meta = apply_filters('auctionforge_term_meta_fields', $term_meta, $this);
        foreach ($term_meta as $key => $termValue) {
            $prevValue = SettingsHelper::getTermOption($id_term, $key);
            if ($termValue != $prevValue) {
                if ($key == 'auction_info') {
                    $termValue = addslashes($termValue);
                }
                update_term_meta($id_term, $key, $termValue, $prevValue);
                $isTermUpdate = true;
            }
        }
        if ($isTermUpdate) {
            Auction::doClearCacheForAuctionPages();
        }
    }

    public function save($auction, $mlPrefix)
    {
        $catParams = array();

        if (empty($auction)) {
            $auction = Auction::findAuctionByNumber($this->getNumber());
        }

        if (!empty($auction->term_id)) {
            if ($mlPrefix) {
                if (PolylangSupport::isPolylangActive() && PolylangSupport::isFullSupport()) {
                    $pllTerms = pll_get_term_translations($auction->term_id);
                    if (isset($pllTerms[$mlPrefix])) {
                        $this->setTermId($pllTerms[$mlPrefix]);
                    }
                } else {
                    $mlPrefix = false;
                    $this->setTermId($auction->term_id);
                }
            } else {
                $this->setTermId($auction->term_id);
            }
        } else {
            $this->setTermId(0);
        }

        if ($this->getName() == "" && $this->getNumber() != "") {
            $this->setName($this->getNumber());
        }

        if ($mlPrefix) {
            $mlPrefix = "-" . $mlPrefix;
        } else {
            $mlPrefix = "";
        }

        if (!empty($auction->term_id)) {
            $catParams = array(
                'cat_ID' => $this->getTermId()
            );
        }

        $catParams = array_merge($catParams, array(
            'category_parent' => 0,
            BidspiritLots::LABEL_TAXONOMY => BidspiritLots::TAX_AUCTION_TYPE
        ));

        if ($this->getName() == "") {
            $this->setName($this->getId());
        }

        if ($this->getId() == sanitize_title($this->getName())) {
            $auctionSlug = $this->getId();
        } else {
            $auctionSlug = $this->getId() . "-" . sanitize_title($this->getName());
        }
        $auctionSlug = LotHelper::chunkSlug(sanitize_title($auctionSlug));
        $auctionSlug = apply_filters('auctionforge_category_nicename_field', $auctionSlug, $auction, $this, "v2", $mlPrefix);
        $mlPrefix = apply_filters('auctionforge_ml_prefix_field', $mlPrefix, $auctionSlug, $auction, $this);

        $catParams = wp_parse_args(array(
            'cat_name' => $this->getName(),
            'category_nicename' => $auctionSlug . $mlPrefix,
        ), $catParams);

        if (!empty($auction->description) && $auction->description != "") {
            $catParams = array_merge($catParams, array(
                'category_description' => $auction->description
            ));
        }

        $id_term = wp_insert_category($catParams, true);

        if ($id_term instanceof \WP_Error) {
            var_dump($catParams, $id_term, $mlPrefix);
            var_dump("----------------------------------------1\r\n");
            Debug::logData([$id_term, $catParams, $mlPrefix], "term_save", array(__FILE__, __LINE__));
            return 0;
        }

        $this->prepareTermMeta($id_term);

        return $id_term;
    }

    public static function doClearCacheForAuctionPages()
    {
        $auctionListKey = 'auction_list';
        $archiveListKey = 'archive_list';
        $manualKey = 'manual_auction_list';
        $pageAuctionListKey = SettingsHelper::getOption($auctionListKey, 0);
        $pageArchiveListKey = SettingsHelper::getOption($archiveListKey, 0);
        $pageManualListKey = SettingsHelper::getOption($manualKey, 0);

        if (PolylangSupport::isPolylangActive()) {
            $pll['pageAuction'] = pll_get_post_translations($pageAuctionListKey);
            $pll['pageArchive'] = pll_get_post_translations($pageArchiveListKey);
            $pll['pageManual'] = pll_get_post_translations($pageManualListKey);

            foreach ($pll as $pages) {
                if (!empty($pages)) {
                    foreach ($pages as $item) {
                        self::clearCacheById($item);
                    }
                }
            }
        }

        HummingbirdSupport::clearCacheByUrl(get_permalink($pageAuctionListKey));
        HummingbirdSupport::clearCacheByUrl(get_permalink($pageArchiveListKey));
        HummingbirdSupport::clearCacheByUrl(get_permalink($pageManualListKey));
        HummingbirdSupport::clearCacheOnHomePage();
    }

    private static function clearCacheById($postId)
    {
        HummingbirdSupport::clearCacheByUrl(get_permalink($postId));
    }

    private function prepareTermMeta($id_term)
    {
        $db = InstanceDB::getInstanceDB();
        $autoCommit = SettingsHelper::isChecked(Settings::AUTO_COMMIT_DISABLED, 'off');
        wp_defer_comment_counting(true);

        InstanceDB::unlockTable();
        if ($autoCommit) {
            $db->query('SET autocommit = 0;');
        }

        $this->updateOptionMeta($id_term);

        wp_defer_comment_counting(false);
        if ($autoCommit) {
            $db->query('COMMIT;');
        }
    }

    public static function getAuctionDayByItemID($lotIndex, $auctionDays)
    {
        $auctionDay = $auctionDays[0];
        $lotIndex = intval($lotIndex);
        if (is_array($auctionDays) && count($auctionDays) > 1) {
            foreach (array_reverse($auctionDays) as $day) {
                if (isset($day->firstLotIndex) && isset($day->lastLotIndex) &&
                    intval($day->firstLotIndex) <= $lotIndex && intval($day->lastLotIndex) >= $lotIndex) {
                    $auctionDay = $day;
                    break;
                }
            }
        }
        return $auctionDay;
    }

    public static function checkTrashTerms()
    {
        $trashTerms = self::getTrashTerms();
        self::clearTrashTerms(apply_filters('auctionforge_trash_terms_filter', $trashTerms));
    }

    public static function getTrashTerms()
    {
        $args = array(
            'post_type'  => 'lot',
            BidspiritLots::LABEL_TAXONOMY => array(BidspiritLots::TAX_AUCTION_TYPE),
            'hide_empty' => 0,
            'meta_query' => array(
                'relation' => 'OR',
                array(
                    'key' => 'auction_id',
                    'compare' => "NOT EXISTS"
                ),
                array(
                    'key' => 'auction_id',
                    'value' => "",
                    'compare' => "="
                )
            ),
            'lang' => ''
        );

        return get_terms($args);
    }

    public static function clearTrashTerms($terms)
    {
        $res = [];
        if (!empty($terms)) {
            foreach ($terms as $term) {
                $termTranslate = [];
                if (PolylangSupport::isPolylangActive()) {
                    $termTranslate = pll_get_term_translations($term->term_id);
                    $issetId = array_search($term->term_id, $termTranslate);
                    if ($issetId !== false) {
                        unset($termTranslate[$issetId]);
                    }
                }
                $res[] = wp_delete_term($term->term_id, self::TERM, ['default' => 0, 'force_default' => true]);
                if (!empty($termTranslate)) {
                    foreach ($termTranslate as $item) {
                        $res[] = wp_delete_term($item, self::TERM, ['default' => 0, 'force_default' => true]);
                    }
                }

                (new Auction)->setLoggedInfo(array(
                    "trash auctions cleared" => [
                        $term, $termTranslate
                    ]
                ));
            }
        }
    }

    /**
     * Get auction number
     * @return string
     */
    public function getNumber()
    {
        return $this->number;
    }

    /**
     * Set auction number
     * @param mixed $number
     */
    public function setNumber($number)
    {
        $this->number = $number;
    }

    /**
     * @return mixed
     */
    public function getAddress()
    {
        return $this->address;
    }

    /**
     * @param mixed $address
     */
    public function setAddress($address)
    {
        $this->address = $address;
    }

    /**
     * @return mixed
     */
    public function getDays()
    {
        return $this->days;
    }

    /**
     * @param mixed $days
     */
    public function setDays($days)
    {
        $this->days = $days;
    }

    public function setDate($days)
    {
        if (!empty($days[0]) && !empty($days[0]->date)) {
            $this->date = $days[0]->date;
        }
        if (!empty($days[0]->time)) {
            $this->date .= " " . $days[0]->time;
        }
    }

    public function getDate()
    {
        return $this->date;
    }

    /**
     * Get auction state
     * @return string
     */
    public function getState()
    {
        return $this->state;
    }

    /**
     * Set auction state
     * @param mixed $state
     */
    public function setState($state)
    {
        $this->state = $state;
    }

    /**
     * @return mixed
     */
    public function getCommissionInfo()
    {
        return $this->commissionInfo;
    }

    /**
     * @param mixed $commissionInfo
     */
    public function setCommissionInfo($commissionInfo)
    {
        $this->commissionInfo = $commissionInfo;
    }

    /**
     * @return mixed
     */
    public function getInfo()
    {
        return $this->info;
    }

    /**
     * @param mixed $info
     */
    public function setInfo($info)
    {
        $this->info = $info;
    }

    /**
     * @return mixed
     */
    public function getDocs()
    {
        return $this->docs;
    }

    /**
     * @param mixed $docs
     */
    public function setDocs($docs)
    {
        $this->docs = $docs;
    }

    /**
     * @return mixed
     */
    public function getDisplayStartPriceInCatalog()
    {
        return $this->displayStartPriceInCatalog;
    }

    /**
     * @param mixed $displayStartPriceInCatalog
     */
    public function setDisplayStartPriceInCatalog($displayStartPriceInCatalog)
    {
        $this->displayStartPriceInCatalog = $displayStartPriceInCatalog;
    }

    /**
     * @return mixed
     */
    public function getShowEstimatedPriceInItemsList()
    {
        return $this->showEstimatedPriceInItemsList;
    }

    /**
     * @param mixed $showEstimatedPriceInItemsList
     */
    public function setShowEstimatedPriceInItemsList($showEstimatedPriceInItemsList)
    {
        $this->showEstimatedPriceInItemsList = $showEstimatedPriceInItemsList;
    }

    /**
     * @return mixed
     */
    public function getCommission()
    {
        return $this->commission;
    }

    /**
     * @param mixed $commission
     */
    public function setCommission($commission)
    {
        $this->commission = $commission;
    }
    
    /**
     * @return mixed
     */
    public function getTermId()
    {
        return $this->termId;
    }

    /**
     * @param  mixed  $termId
     */
    public function setTermId($termId)
    {
        $this->termId = $termId;
    }

    /**
     * @return mixed
     */
    public function getLastCatalogUpdate()
    {
        return $this->lastCatalogUpdate;
    }

    /**
     * @param  mixed  $lastCatalogUpdate
     */
    public function setLastCatalogUpdate($lastCatalogUpdate)
    {
        $this->lastCatalogUpdate = $lastCatalogUpdate;
    }

    /**
     * @return mixed
     */
    public function getAutomaticAuction()
    {
        return $this->automaticAuction;
    }

    /**
     * @param  mixed  $automaticAuction
     */
    public function setAutomaticAuction($automaticAuction)
    {
        $this->automaticAuction = $automaticAuction;
    }
}
