<?php

namespace auctionforge\inc\controllers;

use Kreait\Firebase\Exception\FirebaseException;
use Kreait\Firebase\Exception\MessagingException;
use Kreait\Firebase\Factory;
use stdClass;
use auctionforge\inc\abs\BidspiritWebhooks;
use auctionforge\inc\abs\Importer;
use auctionforge\inc\abs\Model;
use auctionforge\inc\BidSpiritRequest;
use auctionforge\inc\Debug;
use auctionforge\inc\helpers\BS_API;
use auctionforge\inc\helpers\LotHelper;
use auctionforge\inc\helpers\SettingsHelper;
use auctionforge\inc\import\AuctionList;
use auctionforge\inc\import\InsertLotsBS;
use auctionforge\inc\import\LotList;
use auctionforge\inc\model\Auction;
use auctionforge\inc\model\FirebaseLog;
use auctionforge\inc\model\FirebaseUser;
use Kreait\Firebase\Messaging\CloudMessage;
use auctionforge\inc\model\interfaces\AuctionStartsSoon;
use auctionforge\inc\model\interfaces\ItemLiveSoon;
use auctionforge\inc\model\interfaces\LeadingBidSurpassed;
use auctionforge\inc\model\Lot;
use auctionforge\inc\model\LotMetaData;
use auctionforge\inc\traits\LoggerInfo;
use auctionforge\inc\sync\SyncQueue;
use auctionforge\inc\services\BrevoSMS;
use auctionforge\inc\sync\SyncLogger;
use auctionforge\inc\controllers\HummingbirdSupport;
use auctionforge\inc\controllers\MultiLanguageSupport;
use auctionforge\inc\controllers\PolylangSupport;
use auctionforge\inc\controllers\Settings;
use WP_REST_Request;
use WP_REST_Server;

class AuctionsAPI extends BidspiritWebhooks
{
    use LoggerInfo;

    public function init()
    {
        // TODO: Add logs
//        add_action('init', array($this, 'init_app'));
        add_action('rest_api_init', array($this, 'login'));
        add_action('rest_api_init', array($this, 'event'));

        add_action('rest_api_init', array($this, 'status'));
        add_action('rest_api_init', array($this, 'ignore_list'));
        add_action('rest_api_init', array($this, 're_sync'));

        add_action('rest_api_init', array($this, 'get_item_info'));
        //add_action('rest_api_init', array($this, 'setting_update'));

//        add_action('rest_api_init', array($this, 'event'));
        add_action('rest_api_init', array($this, 'translate'));
        add_action('rest_api_init', array($this, 'test_push_notification'));
        add_action('rest_api_init', array($this, 'test_push_public'));
        add_action('rest_api_init', array($this, 'test_bulk_push'));
        
        // Initialize Firebase bulk processing hooks
        add_action('auctionforge_send_firebase_chunk', array($this, 'process_firebase_chunk'));
    }

    public function init_app()
    {
        if (!empty($_GET["app_init"])) {
            $homeUrl = get_option('home');
            header('Refresh:0; url='.$homeUrl);
            exit;
        }
    }

    public function login()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/user/login';

        $rout_params = array(
            'methods' => WP_REST_Server::CREATABLE,
            'callback' => array($this, 'event_login'),
            'args' => array(
                'bidspirit_user_email' => array(
                    'type' => 'string',
                    'required' => true
                ),
                'firebase_id' => array(
                    'type' => 'string',
                    'required' => true
                ),
            ),
            'permission_callback' => function ($request) {
                return $this->checkPermission();
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    public function event_login(WP_REST_Request $request)
    {
        $data = $request->get_params();
        $fireUser = new FirebaseUser();
        $fireUser->loadAttributes($data);
        $fireUser->load();

        if (!empty($fireUser->getFirebaseId())) {
            $fireUser->save();
        }

        return array(
            'request' => $request->get_params(),
            'id' => $fireUser->getId(),
            'email' => $fireUser->getBidspiritUserEmail(),
            'fireId' => $fireUser->getFirebaseId(),
            'created' => $fireUser->getCreated()
        );
    }

    public function event()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/sync';

        $rout_params = array(
            'methods' => ['POST', 'GET'],
            'callback' => array($this, 'event_action'),
            'args' => array(),
            'permission_callback' => function ($request) {
                return $this->checkPermission();
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    public function status()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/status';

        $rout_params = array(
            'methods' => ['POST', 'GET'],
            'callback' => array($this, 'status_action'),
            'args' => array(),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    public function ignore_list()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/ignore-list';

        $rout_params = array(
            'methods' => ['POST', 'GET'],
            'callback' => array($this, 'ignore_list_action'),
            'args' => array(),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    public function re_sync()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/re-sync';

        $rout_params = array(
            'methods' => ['POST', 'GET'],
            'callback' => array($this, 're_sync_action'),
            'args' => array(),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    public function setting_update()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/setting-update';

        $rout_params = array(
            'methods' => ['POST'],
            'callback' => array($this, 'setting_update_action'),
            'args' => array(),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    public function translate()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/translate';

        $rout_params = array(
            'methods' => 'POST',
            'callback' => array($this, 'translate_action'),
            'args' => array(),
            'permission_callback' => function ($request) {
                return $this->checkPermission();
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    public function event_action(WP_REST_Request $request)
    {
        if (!isset($_SERVER['HTTP_X_BIDSPIRIT_SIGNATURE'])) {
            $error = new \WP_Error(500, "You shouldnt be here 1");
            echo $error->get_error_message();
            die;
        }

        $signature = $_SERVER['HTTP_X_BIDSPIRIT_SIGNATURE'];
        /** @var stdClass $response */
        $response = new \stdClass();
        $requestBody = file_get_contents('php://input');
        $authToken = SettingsHelper::getOption('auth_token', '');

        if ($authToken == "" && defined("AUCTIONFORGE_API_TOKEN")) {
            $authToken = AUCTIONFORGE_API_TOKEN;
        }

        $fbResponse = array();
        $obj = new stdClass();

        if (md5($authToken."_".$requestBody) == $signature) {
            $obj = json_decode($requestBody);

            Debug::webhookLog($requestBody, $obj->notificationType);

            switch ($obj->notificationType) {
                case "LEADING_BID_SURPASSED":
                    $fbResponse = $this->leading_bid_surpassed($obj);
                    break;
                case "AUCTION_STARTS_SOON":
                    $fbResponse = $this->auction_starts_soon($obj);
                    break;
                case "ITEM_LIVE_SOON":
                    $fbResponse = $this->item_live_soon($obj);
                    break;
                case "AUCTION_CATALOG_UPDATED":
                    $this->auctionCatalogUpdated($obj);
                    $fbResponse["result"] = true;
                    break;
                case "AUCTION_UPDATED":
                    $this->auctionUpdated($obj);
                    $fbResponse["result"] = true;
                    break;
                case "AUCTION_STATE_UPDATED":
                    $fbResponse["result"] = $this->auctionStateUpdated($obj);
                    break;
                case "AUCTION_PUBLISHED":
                    $this->auctionUpdated($obj);
                    $this->auctionPublishedPush($obj);
                    $fbResponse["result"] = true;
                    break;
                case "CATALOG_PUBLISHED":
                    $this->auctionCatalogUpdated($obj);
                    $this->catalogPublishedPush($obj);
                    $fbResponse["result"] = true;
                    break;
                case "AUCTION_DAY_ENDED":
                    $this->auctionDayEnded($obj);
                    $fbResponse["result"] = true;
                    break;
                case "ITEMS_UPDATED":
                    $this->itemsUpdated($obj);
                    $fbResponse["result"] = true;
                    break;
                case "ANNOUNCEMENT":
                    $this->announcement($obj);
                    $fbResponse["result"] = true;
                    break;
                case "TEST":
                    $fbResponse = $this->test($obj);
                    break;
            }

            if ($fbResponse["result"]) {
                $response->notify = true;
            } else {
                $response->notify = false;
            }
            $response->success = true;
        } else {
            $response->success = false;
            $response->notify = false;
            $response->error = "Bad signature";
        }

        if (!empty($obj->user)) {
            $this->logSave($obj->user, $obj, $requestBody, $fbResponse, $response);
        } elseif (!empty($obj->users)) {
            $this->logSave(json_encode($obj->users), $obj, $requestBody, $fbResponse, $response);
        } else {
            if (isset($obj->notificationType)) {
                $this->logSave($obj->notificationType, $obj, $requestBody, $fbResponse, $response);
            } else {
                $this->logSave("EMPTY_TEST", $obj, $requestBody, $fbResponse, $response);
            }
        }

        echo json_encode($response);
    }

    /**
     * @param  WP_REST_Request  $request
     * @return void
     */
    public function status_action(WP_REST_Request $request)
    {
        $success = false;
        $params = $request->get_params();

        $signature = "";
        /** @var stdClass $response */
        $response = new \stdClass();

        $obj = new \stdClass();
        if (!empty($params)) {
            foreach ($params as $key => $param) {
                $obj->$key = $param;
            }
        }
        $obj = json_decode($obj->params);

        Debug::webhookLog($obj, $obj->notificationType);

        switch ($obj->notificationType) {
            case "AUCTION_CATALOG_UPDATED":
                // implemented — goes through dual-write (enqueue + old handler)
                $this->auctionCatalogUpdated($obj);
                $success = true;
                break;
            case "AUCTION_UPDATED":
                $response->debug = $this->auctionPreventUpdated($obj);
                $success = true;
                break;
            /*case "AUCTION_STATE_UPDATED":
                $fbResponse["result"] = $this->auctionStateUpdated($obj);
                break;*/
            case "AUCTION_DAY_ENDED":
                $this->auctionDayEnded($obj);
                $success = true;
                break;
            case "ITEMS_UPDATED":
                $this->itemsUpdated($obj);
                $success = true;
                break;
            case "TEST":
                $response = $this->test($obj);
                break;
        }

        $response = [
            "success" => $success,
            "result" => $response,
            "body" => $obj,
            "signature" => $signature,
            "params" => $params,
        ];
        echo json_encode($response);
    }

    /**
     * @param  WP_REST_Request  $request
     * @return void
     */
    public function ignore_list_action(WP_REST_Request $request)
    {
        $params = $request->get_params();
        $excludeList = SettingsHelper::getAuctionExclude();
        $auctionId = 0;
        $success = true;
        if (isset($params['auction'])) {
            $auctionId = $params['auction'];
            $key = array_search($auctionId, $excludeList);
            if ($key !== false) {
                unset($excludeList[$key]);

                $separator = "\r\n";
                $newValue = implode($separator, $excludeList);
                SettingsHelper::updateOption("exclude_auction", $newValue);
            }
        } else {
            $success = false;
        }

        global $current_user;

        $user_roles = $current_user->roles;
        $user_role = array_shift($user_roles);

        echo json_encode([
            "success" => $success,
            "auction" => $auctionId,
            "user" => get_current_user_id()
        ]);
    }

    public function re_sync_action(WP_REST_Request $request)
    {
        $args = $request->get_params();
        $result = [];

        if ($args['do'] == 'importBidSpiritUpcoming' || $args['do'] == 'importBidSpiritPast') {
            $upcoming = false;
            if ($args['do'] == 'importBidSpiritUpcoming') {
                $upcoming = true;
            }

            $auctionList = new AuctionList();
            $auctionList->init();

            $errors = $auctionList->getErrors();
            if (!empty($errors)) {
                $logErrors = $auctionList->getErrors();
                Debug::logData($logErrors, "auction-list-ajax");
            }
            $debug["errors"] = $auctionList->getErrors();

            $lotList = new LotList();
            $lotList->setPriority(3);
            $lotList->init(Model::toBoolean($upcoming));
            $errors = $lotList->getErrors();
            if (!empty($errors)) {
                $logErrors = $lotList->getErrors();
                Debug::logData($logErrors, "lot-list-new");
            }

            $result = [
                "success" => true,
                "data" => $auctionList->getErrors(),
                "debug" => $debug,
                "params" => $args
            ];
        } elseif ($args['do'] == 'importData') {
            $insertLots = new InsertLotsBS();
            $insertLots->init($args);

            $result = [
                "success" => true,
                "data" => [],
                "params" => $args
            ];
        }

        echo json_encode($result);
    }

    public function setting_update_action(WP_REST_Request $request)
    {
        $params = $request->get_params();

        $option = $params['option'];
        $value = ($params['value'] == "true") ? "on" : "off";

        $result = SettingsHelper::updateOption($option, $value);

        $result = [
            "success" => $result,
            "params" => $params,
        ];

        echo json_encode($result);
    }

    /**
     * @param $obj LeadingBidSurpassed
     * @return array
     */
    private function leading_bid_surpassed($obj)
    {
        $data = array(
            'request' => array(),
            'response' => array(),
            'result' => true
        );

        $fireUser = new FirebaseUser();
        $fireUser->loadAttributes((array) $obj);
        $fireUser->load();
        $postId = $this->findPostId($obj);

        if ($fireUser->getFirebaseId()) {
            // Safely get permalink - Firebase requires strings only
            $permalink = get_permalink($postId);
            if (!$permalink) {
                $permalink = home_url(); // Fallback to home page
            }
            
            $data["request"] = array(
                'token' => $fireUser->getFirebaseId(),
                'notification' => array(
                    'title' => $obj->auctionNumber."/".$obj->itemIndex." ".__("leading bid surpassed", "auctionforge"),
                    'body' => $obj->itemName,
                    'image' => $this->getFeatureImageByLotId($postId),
                ),
                'data' => array(
                    'url' => (string) $permalink,  // Ensure string type
                    'notificationId' => (string) ($obj->itemId . rand(111, 999))  // Ensure string type
                )
            );

            $data = $this->sendMessage($data);
        }

        // Brevo SMS: outbid notice with cooldown
        if (BrevoSMS::isNotificationEnabled('outbid') && !empty($obj->user)) {
            $permalink = get_permalink($postId) ?: home_url();
            $smsContent = BrevoSMS::buildOutbidMessage(
                $obj->itemIndex ?? '',
                $obj->itemName ?? '',
                $permalink
            );
            BrevoSMS::sendOutbidNotice($obj->user, $obj->itemId ?? '', $smsContent);
        }

        return $data;
    }

    /**
     * @param $obj ItemLiveSoon
     * @return array
     */
    private function item_live_soon($obj)
    {
        $data = array(
            'request' => array(),
            'response' => array(),
            'result' => true
        );

        $deviceTokens = FirebaseUser::deviceTokensForUsers($obj->users);
        $postId = $this->findPostId($obj);
        if (!empty($deviceTokens)) {
            // Safely get permalink - Firebase requires strings only
            $permalink = get_permalink($postId);
            if (!$permalink) {
                $permalink = home_url(); // Fallback to home page
            }
            
            $data["request"] = array(
                'notification' => array(
                    'title' => $obj->auctionNumber."/".$obj->itemIndex." ".__("item live soon", "auctionforge"),
                    'body' => $obj->itemName,
                    'image' => $this->getFeatureImageByLotId($postId),
                    'imageUrl' => $this->getFeatureImageByLotId($postId)
                ),
                'data' => array(
                    'url' => (string) $permalink,  // Ensure string type
                    'notificationId' => (string) ($obj->itemId . rand(111, 999))  // Ensure string type
                )
            );

            $data = $this->sendMessage($data, $deviceTokens);
        }

        // Brevo SMS: item live soon to favorited users
        if (BrevoSMS::isNotificationEnabled('item_live_soon') && !empty($obj->users)) {
            $permalink = get_permalink($postId) ?: home_url();
            $smsContent = BrevoSMS::buildItemLiveSoonMessage(
                $obj->itemIndex ?? '',
                $obj->itemName ?? '',
                $obj->auctionNumber ?? '',
                $permalink
            );
            BrevoSMS::sendToUsers($obj->users, 'item_live_soon', $smsContent, 'item_live_soon');
        }

        return $data;
    }

    /**
     * @param $obj AuctionStartsSoon
     * @return array
     */
    private function auction_starts_soon($obj)
    {
        $data = array(
            'request' => array(),
            'response' => array(),
            'result' => true
        );

        $deviceTokens = FirebaseUser::deviceTokensForUsers($obj->users);
        $termId = $this->findTermId($obj);
        if (!empty($deviceTokens)) {
            // Safely get term link - Firebase requires strings only
            $termLink = get_term_link($termId);
            if (is_wp_error($termLink) || !$termLink) {
                $termLink = home_url(); // Fallback to home page
            }
            
            $data["request"] = array(
                'notification' => array(
                    'title' => $obj->auctionNumber." ".__("auction starts soon", "auctionforge"),
                    'body' => $obj->auctionName,
                    'image' => $this->getFeatureImageByAuctionId($obj, $termId),
                    'imageUrl' => $this->getFeatureImageByAuctionId($obj, $termId)
                ),
                'data' => array(
                    'url' => (string) $termLink,  // Ensure string type
                    'notificationId' => (string) ($obj->auctionId . rand(111, 999))  // Ensure string type
                )
            );

            $data = $this->sendMessage($data, $deviceTokens);
        }

        // Brevo SMS: auction starts soon to registered users
        if (BrevoSMS::isNotificationEnabled('auction_starts_soon') && !empty($obj->users)) {
            $termLink = get_term_link($termId);
            $url = (is_wp_error($termLink) || !$termLink) ? home_url() : $termLink;
            $smsContent = BrevoSMS::buildAuctionStartsSoonMessage(
                $obj->auctionNumber ?? '',
                $obj->auctionName ?? '',
                $url
            );
            BrevoSMS::sendToUsers($obj->users, 'auction_starts_soon', $smsContent, 'auction_starts_soon');
        }

        return $data;
    }

    private function sendMessage($data, $deviceTokens = array())
    {
        $messaging = $this->getFactoryMessaging();
        $message = CloudMessage::fromArray($data["request"])->withDefaultSounds();
        
        // Production monitoring - only essential metrics
        $monitoringInfo = array(
            'tokens_count' => count($deviceTokens),
            'sending_method' => !empty($deviceTokens) ? 'multiple' : 'single'
        );
        
        try {
            if (!empty($deviceTokens)) {
                // Performance optimization: Limit tokens per request
                $maxTokensPerBatch = apply_filters('auctionforge_firebase_max_tokens_per_batch', 50);
                $originalTokenCount = count($deviceTokens);
                
                if ($originalTokenCount > $maxTokensPerBatch) {
                    $deviceTokens = array_slice($deviceTokens, 0, $maxTokensPerBatch);
                    $monitoringInfo['tokens_limited'] = true;
                    $monitoringInfo['original_count'] = $originalTokenCount;
                    $monitoringInfo['processed_count'] = count($deviceTokens);
                }
                
                $successCount = 0;
                $failureCount = 0;
                $startTime = microtime(true);
                
                foreach ($deviceTokens as $index => $token) {
                    try {
                        // Timeout protection
                        $elapsedTime = microtime(true) - $startTime;
                        if ($elapsedTime > 25) {
                            $monitoringInfo['timeout_reached'] = true;
                            $monitoringInfo['stopped_at_index'] = $index;
                            break;
                        }
                        
                        // Send individual message
                        $tokenMessage = $message->withChangedTarget('token', $token);
                        $messaging->send($tokenMessage);
                        $successCount++;
                        
                        // Rate limiting pause
                        if ($successCount % 10 == 0) {
                            usleep(100000);
                        }
                        
                    } catch (MessagingException $e) {
                        $failureCount++;
                        // Log only critical errors for production monitoring
                        if ($failureCount === 1) {
                            $monitoringInfo['first_error'] = $e->getMessage();
                        }
                    } catch (FirebaseException $e) {
                        $failureCount++;
                        if ($failureCount === 1) {
                            $monitoringInfo['first_error'] = $e->getMessage();
                        }
                    }
                }
                
                $totalTime = microtime(true) - $startTime;
                
                $data["response"] = array(
                    'successCount' => $successCount,
                    'failureCount' => $failureCount,
                    'totalTime' => round($totalTime, 2)
                );
                
                $monitoringInfo['success_count'] = $successCount;
                $monitoringInfo['failure_count'] = $failureCount;
                $monitoringInfo['total_time'] = round($totalTime, 2);
                $monitoringInfo['success_rate'] = $successCount > 0 ? round(($successCount / ($successCount + $failureCount)) * 100, 1) : 0;
                
                $data["result"] = $successCount > 0;
                
            } else {
                $monitoringInfo['sending_method'] = 'single';
                $data["response"] = $messaging->send($message);
            }
        } catch (MessagingException $e) {
            $data["response"]["MessagingException"] = $e->getMessage();
            $data["result"] = false;
            $monitoringInfo['critical_error'] = $e->getMessage();
        } catch (FirebaseException $e) {
            $data["response"]["FirebaseException"] = $e->getMessage();
            $data["result"] = false;
            $monitoringInfo['critical_error'] = $e->getMessage();
        }
        
        // Log only if there are issues or significant batches for production monitoring
        if (isset($monitoringInfo['critical_error']) || 
            isset($monitoringInfo['timeout_reached']) || 
            $monitoringInfo['tokens_count'] > 10 ||
            (isset($monitoringInfo['failure_count']) && $monitoringInfo['failure_count'] > 0)) {
            
            Debug::logData($monitoringInfo, 'firebase_notifications');
        }
        
        return $data;
    }

    /**
     * @param $obj stdClass
     * @return array
     */
    private function test($obj)
    {
        $data = array(
            'request' => array(),
            'response' => array(),
            'result' => true
        );

        $deviceTokens = FirebaseUser::deviceTokensForUsers([
            'support@smoothbyteit.dev',
            'support@bidspirit-themes.com'
        ]);
        
        if (!empty($deviceTokens)) {
            $data["request"] = array(
                'notification' => array(
                    'title' => "Test notice",
                    'body' => "Body test notice",
                ),
                'data' => array(
                    'notificationId' => (string) ('1001' . rand(111, 999))  // Ensure string type
                )
            );

            $data['response'] = $this->sendMessage($data, $deviceTokens);
        }

        return $data;
    }

    /**
     * @param $fireUser string
     * @param $obj stdClass
     * @param $requestBody string
     * @param $fbResponse array
     * @param $response stdClass
     * @return void
     */
    private function logSave($user, $obj, $requestBody, $fbResponse, $response)
    {
        $attr = array(
            'firebase_id' => $user,
            'bidspirit_user_email' => (!empty($obj->user)) ? $obj->user : "",
            'bidspirit_lot_id' => (!empty($obj->itemIndex)) ? $obj->itemIndex : "",
            'request_from_bidspirit' => $requestBody,
            'request_to_firebase' => (!empty($fbResponse["request"])) ? $fbResponse["request"] : "",
            'response_from_firebase' => (!empty($fbResponse["response"])) ? $fbResponse["response"] : "",
            'response_to_bidspirit' => $response
        );

        $fireLog = new FirebaseLog(FirebaseLog::STATUS_SENT);
        $fireLog->loadAttributes($attr);
        $fireLog->save();
    }

    /**
     * @return \Kreait\Firebase\Contract\Messaging
     */
    private function getFactoryMessaging()
    {
        if (!defined('AUCTIONFORGE_SERVICE_PACK')) {
            define('AUCTIONFORGE_SERVICE_PACK', 'service');
        }

        $service = require_once __DIR__.'/../services/'.AUCTIONFORGE_SERVICE_PACK.'.php';
        $factoryInstance = new Factory();
        $factory = $factoryInstance->withServiceAccount($service);
        return $factory->createMessaging();
    }

    /**
     * @param $obj LeadingBidSurpassed|ItemLiveSoon
     * @return int|void
     */
    private function findPostId($obj)
    {
        if (PolylangSupport::isPolylangActive() && PolylangSupport::isFullSupport()) {
            $langCode = pll_default_language();
        } else {
            $langCode = '';
        }

        $posts = Lot::findLotByLotID($obj->itemId, 0, $langCode);
        if (!empty($posts) && isset($posts[0])) {
            return $posts[0]->ID;
        }
    }

    /**
     * @param $obj AuctionStartsSoon
     * @return int
     */
    private function findTermId($obj)
    {
        $auction = Auction::findAuctionById($obj->auctionId);
        if (!empty($auction->term_id)) {
            return $auction->term_id;
        } else {
            return 0;
        }
    }

    /**
     * @param $postId int
     * @return string|null
     */
    private function getFeatureImageByLotId($postId)
    {
        return LotHelper::getFeatureImageByID($postId);
    }

    /**
     * @param $obj AuctionStartsSoon
     * @param $termId int
     * @return string
     */
    private function getFeatureImageByAuctionId($obj, $termId)
    {
        $auctionDays = SettingsHelper::getTermOption($termId, 'auction_days');
        $dayIndex = (!empty($obj->dayIndex)) ? intval($obj->dayIndex) - 1 : 0;
        if (!empty($auctionDays[$dayIndex]->image)) {
            $featureImage = $auctionDays[$dayIndex]->image;
        } else {
            $featureImage = LotHelper::getPlaceholderImage();
        }
        return $featureImage;
    }

    /**
     * Update auction catalog.
     * @param $obj
     * @return void
     */
    private function auctionCatalogUpdated($obj)
    {
        Debug::dumpToFile($obj);

        // Sync v3: enqueue job + spawn worker (new path)
        $jobId = SyncQueue::enqueue(
            SyncQueue::TYPE_CATALOG_SYNC,
            $obj->auctionId,
            $obj,
            1,
            'webhook'
        );
        if ($jobId) {
            SyncQueue::spawnWorker();
        }
    }

    private function auctionPreventUpdated($obj)
    {
        $debug = [];
        $langCode = SettingsHelper::getOption("lang", 'en');

        $debug[] = [$obj->term, $obj->auctionId, $langCode];
        $auctionInfo = Auction::getAuctionInfo($obj->auctionId, $langCode);
        $this->updateAuction($auctionInfo, $langCode);

        if (PolylangSupport::isPolylangActive() && PolylangSupport::isFullSupport()) {
            $secondLangCode = MultiLanguageSupport::getSecondLangCode();

            $term = Auction::findAuctionByIdWithLang($obj->auctionId, $secondLangCode);
            if (!empty($term)) {
                $auctionInfo = Auction::getAuctionInfo($obj->auctionId, $secondLangCode);
                $this->updateAuction($auctionInfo, $secondLangCode);

                $debug[] = [$term, $obj->auctionId, $secondLangCode];
            }

            $otherLanguages = PolylangSupport::getSupportedLanguages();
            if (!empty($otherLanguages['other'])) {
                foreach ($otherLanguages['other'] as $otherLanguage) {
                    $term = Auction::findAuctionByIdWithLang($obj->auctionId, $otherLanguage);
                    if (!empty($term)) {
                        $defaultLang = SettingsHelper::getOption(Settings::OPTIONS_OTHER_LANG, 'default');
                        $auctionInfo = Auction::getAuctionInfo($obj->auctionId, $defaultLang);
                        $this->updateAuction($auctionInfo, $otherLanguage);
                        $debug[] = [$term, $obj->auctionId, $otherLanguage];
                    }
                }
            }
        }

        return $debug;
    }

    private function auctionUpdated($obj)
    {
        //Debug::logData($obj);
        $langCode = SettingsHelper::getOption("lang", 'en');
        $response = $obj->auctionsInfoByLang;
        $category = $response->{$langCode};
        $terms = [];

        if (isset($category->hidden) && $category->hidden == true) {
            return;
        }

        Auction::checkTrashTerms();

        $terms[$langCode] = $this->updateAuction($category, $langCode);

        if (PolylangSupport::isPolylangActive() && PolylangSupport::isFullSupport()) {
            $secondLangCode = MultiLanguageSupport::getSecondLangCode();
            $categorySecond = $response->{$secondLangCode};
            $terms[$secondLangCode] = $this->updateAuction($categorySecond, $secondLangCode);

            $otherLanguages = PolylangSupport::getSupportedLanguages();
            if (!empty($otherLanguages['other'])) {
                foreach ($otherLanguages['other'] as $otherLanguage) {
                    $terms[$otherLanguage] = $this->updateAuction($category, $otherLanguage);
                }
            }

            $fields = json_encode([
                "terms" => $terms,
                "defaultLang" => $langCode,
                "secondLang" => $secondLangCode,
                "other" => $otherLanguages
            ]);

            $this->translateRequest($fields);
        }

        Auction::doClearCacheForAuctionPages();
    }

    private function updateAuction($category, $mlPrefix)
    {
        $model = new Auction();
        $model->loadAttributes($category);
        $model->setDate($model->getDays());

        if (!PolylangSupport::isPolylangActive()) {
            $mlPrefix = false;
        }

        $auction = Auction::findAuctionByIdWithLang($model->getId(), $mlPrefix);

        if ($auction instanceof \WP_Term) {
            $model->setTermId($auction->term_id);
        }

        return $model->save($auction, $mlPrefix);
    }

    /**
     * @param $obj stdClass
     * @return void
     */
    private function itemsUpdated($obj)
    {
        // Sync v3: enqueue item update job (new path)
        // ITEMS_UPDATED payload has auctionId nested in itemsByLanguage.{lang}[0].item.auctionId
        $auctionId = !empty($obj->auctionId) ? $obj->auctionId : null;
        if (empty($auctionId) && !empty($obj->itemsByLanguage)) {
            $langCode = SettingsHelper::getOption("lang", 'en');
            $langItems = isset($obj->itemsByLanguage->{$langCode}) ? $obj->itemsByLanguage->{$langCode} : null;
            if (!empty($langItems[0]->item->auctionId)) {
                $auctionId = $langItems[0]->item->auctionId;
            }
        }

        if (!empty($auctionId)) {
            $jobId = SyncQueue::enqueue(
                SyncQueue::TYPE_ITEM_UPDATE,
                $auctionId,
                $obj,
                2,
                'webhook'
            );
            if ($jobId) {
                SyncQueue::spawnWorker();
            }
        }
    }

    /**
     * Send push notification
     * @param $obj stdClass
     * @return array
     */
    private function auctionPublishedPush($obj)
    {
        $deviceTokens = FirebaseUser::deviceTokens();
        $data = array(
            'request' => array(),
            'response' => array(),
            'result' => true
        );
        $termId = $this->findTermId($obj);

        $langCode = SettingsHelper::getOption("lang", 'en');
        if ($obj->auctionsInfoByLang[$langCode]) {
            $obj->auctionName = $obj->auctionsInfoByLang[$langCode]->name;
        } else {
            $obj->auctionName = $obj->auctionNumber;
        }

        if (!empty($deviceTokens)) {
            // Safely get permalink - Firebase requires strings only
            $auctionListId = SettingsHelper::getOption('auction_list', 0);
            $permalink = get_permalink($auctionListId);
            if (!$permalink) {
                $permalink = home_url(); // Fallback to home page
            }
            
            $data["request"] = array(
                'notification' => array(
                    'title' => $obj->auctionNumber." ".__("auction published", "auctionforge"),
                    'body' => $obj->auctionName,
                    'image' => $this->getFeatureImageByAuctionId($obj, $termId),
                    'imageUrl' => $this->getFeatureImageByAuctionId($obj, $termId)
                ),
                'data' => array(
                    'url' => (string) $permalink,  // Ensure string type
                    'notificationId' => (string) ($obj->auctionId . rand(111, 999))  // Ensure string type
                )
            );

            $data = $this->sendMessage($data, $deviceTokens);
            Auction::doClearCacheForAuctionPages();
        }

        // Brevo SMS: auction published broadcast to all opted-in subscribers
        if (BrevoSMS::isNotificationEnabled('auction_published')) {
            $auctionListId = SettingsHelper::getOption('auction_list', 0);
            $url = get_permalink($auctionListId) ?: home_url();
            $smsContent = BrevoSMS::buildAuctionPublishedMessage(
                $obj->auctionNumber ?? '',
                $obj->auctionName ?? '',
                $url
            );
            BrevoSMS::sendBroadcast('auction_published', $smsContent, 'auction_published');
        }

        return $data;
    }

    /**
     * Send push notifications.
     * @param $obj
     * @return array
     */
    private function catalogPublishedPush($obj)
    {
        $deviceTokens = FirebaseUser::deviceTokens();
        $data = array(
            'request' => array(),
            'response' => array(),
            'result' => true
        );
        $termId = $this->findTermId($obj);
        if (!empty($deviceTokens)) {
            // Safely get term link - Firebase requires strings only
            $termLink = get_term_link($termId);
            if (is_wp_error($termLink) || !$termLink) {
                $termLink = home_url(); // Fallback to home page
            }
            
            $data["request"] = array(
                'notification' => array(
                    'title' => $obj->auctionNumber." ".__("catalog published", "auctionforge"),
                    'body' => $obj->auctionName,
                    'image' => $this->getFeatureImageByAuctionId($obj, $termId),
                    'imageUrl' => $this->getFeatureImageByAuctionId($obj, $termId)
                ),
                'data' => array(
                    'url' => (string) $termLink,  // Ensure string type
                    'notificationId' => (string) ($obj->auctionId . rand(111, 999))  // Ensure string type
                )
            );

            $data = $this->sendMessage($data, $deviceTokens);
            Auction::doClearCacheForAuctionPages();
        }

        return $data;
    }

    private function auctionDayEnded($obj)
    {
        $auctionId = $obj->auctionId;

        // Sync v3: enqueue day ended job (new path)
        $jobId = SyncQueue::enqueue(
            SyncQueue::TYPE_DAY_ENDED,
            $auctionId,
            $obj,
            1,
            'webhook'
        );
        if ($jobId) {
            SyncQueue::spawnWorker();
        }
    }

    private function updateCatalogAction($auctionId)
    {
        if (!empty($auctionId)) {
            $lotList = new LotList();
            $lotList->setPriority(2);
            // TODO: Implement Multilanguage for full delete lots
            $lotList->singleRun($auctionId);
            if (!empty($lotList->getErrors())) {
                $errors = $lotList->getErrors();
                Debug::logData($errors, "lot-list-new");
            }
        }
    }

    private function auctionStateUpdated($obj)
    {
        $response = $obj;
        $auctionId = $response->auctionId;
        $state = $response->state;

        if ($auctionId == "" || $state == "") {
            return false;
        }

        $langCode = SettingsHelper::getOption("lang", 'en');
        $term = BS_API::findAuctionByIdWithLang($auctionId, $langCode);

        if (!($term instanceof \WP_Term)) {
            return false;
        }

        $prevValue = BS_API::getTermOption($term->term_id, 'auction_state');
        update_term_meta($term->term_id, 'auction_state', $state, $prevValue);

        if (PolylangSupport::isPolylangActive() && PolylangSupport::isFullSupport()) {
            $secondLangCode = MultiLanguageSupport::getSecondLangCode();
            $term = BS_API::findAuctionByIdWithLang($auctionId, $secondLangCode);
            update_term_meta($term->term_id, 'auction_state', $state, $prevValue);

            $otherLanguages = PolylangSupport::getSupportedLanguages();
            if (!empty($otherLanguages['other'])) {
                foreach ($otherLanguages['other'] as $otherLanguage) {
                    $term = BS_API::findAuctionByIdWithLang($auctionId, $otherLanguage);
                    update_term_meta($term->term_id, 'auction_state', $state, $prevValue);
                }
            }
        }

        Auction::doClearCacheForAuctionPages();

        return true;
    }

    private function announcement($obj)
    {
        $deviceTokens = FirebaseUser::deviceTokens();
        $data = [];
        if (!empty($deviceTokens)) {
            $data["request"] = array(
                'notification' => array(
                    'title' => "",
                    'body' => $obj->message,
                ),
                'data' => array(
                    'notificationId' => (string) ($obj->itemId . rand(111, 999))  // Ensure string type
                )
            );

            $data = $this->sendMessage($data, $deviceTokens);
        }
        return $data;
    }

    private function buildItem($item, $itemSecond)
    {
        $item->lotId = $item->id;
        $item->auctionSlug = $item->auctionId;
        $item->syncTimes = 0;
        $item->priority = 1;
        $item->createDatetime = date(Importer::DATE_FORMAT);

        if (isset($itemSecond->name)) {
            $item->nameL2 = $itemSecond->name;
        } else {
            $item->nameL2 = $item->name;
        }

        if (isset($itemSecond->description)) {
            $item->descriptionL2 = $itemSecond->description;
        } else {
            $item->descriptionL2 = $item->description;
        }

        if (isset($itemSecond->author)) {
            $item->authorL2 = $itemSecond->author;
        } else {
            $item->authorL2 = $item->author;
        }

        return $item;
    }

    /**
     * @param $item stdClass
     * @param $leadingBid stdClass
     * @return stdClass
     */
    private function leadingBid($leadingBid, $item)
    {
        if (!empty($leadingBid) && isset($leadingBid->price)) {
            $item->leadingBid = $leadingBid->price;
        } else {
            $item->leadingBid = 0;
        }

        return $item;
    }

    private function soldBid($soldBid, $item)
    {
        if (!empty($soldBid) && isset($soldBid->price)) {
            $item->soldBid = $soldBid->price;
        }
        return $item;
    }

    private function translateRequest($fields)
    {
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => get_option('siteurl').'/wp-json/bidspirit/v1/translate',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => $fields,
            CURLOPT_HTTPHEADER => array(
                'Bidspirit-User-Agent: Web2Application',
                'HTTP_X_BIDSPIRIT_SIGNATURE: update',
                'Content-Type: application/json'
            ),
        ));
        curl_exec($curl);
    }

    /*private function webhookRequest($fields, $signature)
    {
        $_SERVER["HTTP_X_BIDSPIRIT_SIGNATURE"] = $signature;
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => get_option('siteurl').'/wp-json/bidspirit/v1/sync',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => $fields,
            CURLOPT_HTTPHEADER => array(
                'Bidspirit-User-Agent: Web2Application',
                'HTTP_X_BIDSPIRIT_SIGNATURE: '.$signature,
                'Content-Type: application/x-www-form-urlencoded'
            ),
        ));
        return curl_exec($curl);
    }*/

    public function translate_action(WP_REST_Request $request)
    {
        if (!(isset($_SERVER['HTTP_BIDSPIRIT_USER_AGENT']) && $_SERVER['HTTP_BIDSPIRIT_USER_AGENT'] == "Web2Application")) {
            $error = new \WP_Error(500, "You shouldnt be here");
            echo $error->get_error_message();
            die;
        }

        $params = $request->get_json_params();
        pll_set_term_language($params["terms"][$params["defaultLang"]], $params["defaultLang"]);
        pll_set_term_language($params["terms"][$params["secondLang"]], $params["secondLang"]);

        if (!empty($params['other']['other'])) {
            $otherLanguages = $params['other']['other'];
            foreach ($otherLanguages as $item) {
                pll_set_term_language($params["terms"][$item], $item);
            }
        }

        pll_save_term_translations($params["terms"]);
    }

    public function get_item_info()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/item-info/';

        $rout_params = array(
            'methods' => 'POST',
            'callback' => array($this, 'get_item_info_action'),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    public function get_item_info_action(WP_REST_Request $request)
    {
        $params = $request->get_params();
        $lotData = LotMetaData::getMetaDataByLotId($params['lotId']);
        $termId = LotMetaData::getMetaFieldByLotId('termId', $params['lotId']);
        $auctionId = SettingsHelper::getTermOption($termId, 'auction_id');
        $lang = MultiLanguageSupport::getDefaultLangCode();
        $success = true;

        if (empty($lotData)) {
            $success = false;
        }

        echo json_encode([
            'success' => $success,
            'params' => $params,
            'data' => $lotData,
            'auctionId' => $auctionId,
            'lang' => $lang,
        ]);
    }

    /**
     * Register REST API endpoint for testing push notifications
     */
    public function test_push_notification()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/test-push';

        $rout_params = array(
            'methods' => 'POST',
            'callback' => array($this, 'test_push_notification_action'),
            'args' => array(
                'notificationType' => array(
                    'type' => 'string',
                    'required' => true,
                    'description' => 'Type of notification to test',
                    'enum' => array(
                        'LEADING_BID_SURPASSED',
                        'AUCTION_STARTS_SOON',
                        'ITEM_LIVE_SOON',
                        'AUCTION_PUBLISHED',
                        'CATALOG_PUBLISHED',
                        'ANNOUNCEMENT',
                        'TEST'
                    )
                ),
                'testUser' => array(
                    'type' => 'string',
                    'required' => false,
                    'description' => 'Email of test user (optional, defaults to test users)'
                ),
                'customData' => array(
                    'type' => 'object',
                    'required' => false,
                    'description' => 'Custom data for notification (optional)'
                )
            ),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    /**
     * Handle test push notification request
     */
    public function test_push_notification_action(WP_REST_Request $request)
    {
        $params = $request->get_params();
        $notificationType = $params['notificationType'];
        $testUser = $params['testUser'] ?? null;
        $customData = $params['customData'] ?? array();

        $response = array(
            'success' => false,
            'message' => '',
            'data' => array(),
            'params' => $params
        );

        try {
            // Create test notification object based on type
            $obj = $this->createTestNotificationObject($notificationType, $testUser, $customData);
            
            // Send notification
            $fbResponse = $this->processTestNotification($notificationType, $obj);
            
            $response['success'] = true;
            $response['message'] = 'Test notification sent successfully';
            $response['data'] = $fbResponse;
            
        } catch (Exception $e) {
            $response['success'] = false;
            $response['message'] = 'Error sending test notification: ' . $e->getMessage();
            $response['error'] = $e->getMessage();
        }

        echo json_encode($response);
    }

    /**
     * Register PUBLIC REST API endpoint for testing push notifications WITHOUT authentication
     * ВНИМАНИЕ: Только для тестирования! Отключите в production!
     */
    public function test_push_public()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/test-push-public';

        $rout_params = array(
            'methods' => 'POST',
            'callback' => array($this, 'test_push_public_action'),
            'args' => array(
                'notificationType' => array(
                    'type' => 'string',
                    'required' => true,
                    'description' => 'Type of notification to test',
                    'enum' => array(
                        'LEADING_BID_SURPASSED',
                        'AUCTION_STARTS_SOON',
                        'ITEM_LIVE_SOON',
                        'AUCTION_PUBLISHED',
                        'CATALOG_PUBLISHED',
                        'ANNOUNCEMENT',
                        'TEST'
                    )
                ),
                'testUser' => array(
                    'type' => 'string',
                    'required' => false,
                    'description' => 'Email of test user (optional, defaults to test users)'
                ),
                'customData' => array(
                    'type' => 'object',
                    'required' => false,
                    'description' => 'Custom data for notification (optional)'
                ),
                'testKey' => array(
                    'type' => 'string',
                    'required' => true,
                    'description' => 'Test key for security (use: test_firebase_2024)'
                )
            ),
            'permission_callback' => function ($request) {
                // Публичный endpoint - проверяем только тестовый ключ
                return true;
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    /**
     * Handle PUBLIC test push notification request (без авторизации)
     */
    public function test_push_public_action(WP_REST_Request $request)
    {
        $params = $request->get_params();
        $testKey = $params['testKey'] ?? '';
        
        // Простая проверка тестового ключа
        if ($testKey !== 'test_firebase_2024') {
            echo json_encode(array(
                'success' => false,
                'message' => 'Invalid test key. Use: test_firebase_2024',
                'params' => $params
            ));
            return;
        }

        $notificationType = $params['notificationType'];
        $testUser = $params['testUser'] ?? null;
        $customData = $params['customData'] ?? array();

        $response = array(
            'success' => false,
            'message' => '',
            'data' => array(),
            'params' => $params,
            'note' => 'PUBLIC TEST ENDPOINT - Только для отладки!'
        );

        try {
            // Create test notification object based on type
            $obj = $this->createTestNotificationObject($notificationType, $testUser, $customData);
            
            // Send notification
            $fbResponse = $this->processTestNotification($notificationType, $obj);
            
            $response['success'] = true;
            $response['message'] = 'Test notification sent successfully (PUBLIC MODE)';
            $response['data'] = $fbResponse;
            
        } catch (Exception $e) {
            $response['success'] = false;
            $response['message'] = 'Error sending test notification: ' . $e->getMessage();
            $response['error'] = $e->getMessage();
        }

        echo json_encode($response);
    }

    /**
     * Create test notification object based on type
     */
    private function createTestNotificationObject($notificationType, $testUser = null, $customData = array())
    {
        $obj = new stdClass();
        $obj->notificationType = $notificationType;

        // Default test users
        $defaultTestUsers = array(
            'support@smoothbyteit.dev',
            'support@bidspirit-themes.com'
        );

        switch ($notificationType) {
            case 'LEADING_BID_SURPASSED':
                $obj->user = $testUser ?? 'support@smoothbyteit.dev';
                $obj->auctionNumber = $customData['auctionNumber'] ?? 'TEST-001';
                $obj->itemIndex = $customData['itemIndex'] ?? '1';
                $obj->itemName = $customData['itemName'] ?? 'Test Item for Leading Bid';
                $obj->itemId = $customData['itemId'] ?? '12345';
                $obj->auctionId = $customData['auctionId'] ?? '1';
                break;

            case 'AUCTION_STARTS_SOON':
                $obj->users = $testUser ? array($testUser) : $defaultTestUsers;
                $obj->auctionNumber = $customData['auctionNumber'] ?? '220';
                $obj->auctionName = $customData['auctionName'] ?? 'Test Auction Starting Soon';
                $obj->auctionId = $customData['auctionId'] ?? '220';
                if ($customData['dayIndex']) {
                    $obj->dayIndex = $customData['dayIndex'];
                }
                break;

            case 'ITEM_LIVE_SOON':
                $obj->users = $testUser ? array($testUser) : $defaultTestUsers;
                $obj->auctionNumber = $customData['auctionNumber'] ?? 'TEST-003';
                $obj->itemIndex = $customData['itemIndex'] ?? '5';
                $obj->itemName = $customData['itemName'] ?? 'Test Item Going Live';
                $obj->itemId = $customData['itemId'] ?? '54321';
                $obj->auctionId = $customData['auctionId'] ?? '3';
                break;

            case 'AUCTION_PUBLISHED':
                $obj->auctionNumber = $customData['auctionNumber'] ?? 'TEST-004';
                $obj->auctionName = $customData['auctionName'] ?? 'Test Published Auction';
                $obj->auctionId = $customData['auctionId'] ?? '4';
                break;

            case 'CATALOG_PUBLISHED':
                $obj->auctionNumber = $customData['auctionNumber'] ?? 'TEST-005';
                $obj->auctionName = $customData['auctionName'] ?? 'Test Published Catalog';
                $obj->auctionId = $customData['auctionId'] ?? '5';
                break;

            case 'ANNOUNCEMENT':
                $obj->message = $customData['message'] ?? 'Test announcement message';
                $obj->itemId = $customData['itemId'] ?? '99999';
                break;

            case 'TEST':
                $obj->users = $testUser ? array($testUser) : $defaultTestUsers;
                break;

            default:
                throw new Exception('Unknown notification type: ' . $notificationType);
        }

        return $obj;
    }

    /**
     * Process test notification and send push message
     */
    private function processTestNotification($notificationType, $obj)
    {
        $fbResponse = array();

        switch ($notificationType) {
            case 'LEADING_BID_SURPASSED':
                $fbResponse = $this->leading_bid_surpassed($obj);
                break;
            case 'AUCTION_STARTS_SOON':
                $fbResponse = $this->auction_starts_soon($obj);
                break;
            case 'ITEM_LIVE_SOON':
                $fbResponse = $this->item_live_soon($obj);
                break;
            case 'AUCTION_PUBLISHED':
                $fbResponse = $this->auctionPublishedPush($obj);
                break;
            case 'CATALOG_PUBLISHED':
                $fbResponse = $this->catalogPublishedPush($obj);
                break;
            case 'ANNOUNCEMENT':
                $fbResponse = $this->announcement($obj);
                break;
            case 'TEST':
                $fbResponse = $this->test($obj);
                break;
            default:
                throw new Exception('Unknown notification type: ' . $notificationType);
        }

        return $fbResponse;
    }

    /**
     * Initialize testing helper endpoints
     */
    public function init_test_helpers()
    {
        add_action('rest_api_init', array($this, 'firebase_logs'));
        add_action('rest_api_init', array($this, 'firebase_users'));
        add_action('rest_api_init', array($this, 'clear_firebase_logs'));
        add_action('rest_api_init', array($this, 'firebase_status'));
        add_action('rest_api_init', array($this, 'firebase_status_public'));
    }

    /**
     * Get Firebase logs for debugging
     */
    public function firebase_logs()
    {
        register_rest_route(self::API_NAMESPACE, '/firebase-logs', array(
            'methods' => 'GET',
            'callback' => array($this, 'firebase_logs_action'),
            'args' => array(
                'limit' => array(
                    'type' => 'integer',
                    'default' => 50,
                    'minimum' => 1,
                    'maximum' => 500
                ),
                'offset' => array(
                    'type' => 'integer',
                    'default' => 0,
                    'minimum' => 0
                ),
                'user' => array(
                    'type' => 'string',
                    'required' => false
                )
            ),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            }
        ));
    }

    /**
     * Get Firebase logs action
     */
    public function firebase_logs_action(WP_REST_Request $request)
    {
        global $wpdb;
        
        $params = $request->get_params();
        $limit = $params['limit'];
        $offset = $params['offset'];
        $user = $params['user'] ?? null;
        
        $table_name = $wpdb->prefix . 'firebase_logs';
        
        $where_clause = '';
        if ($user) {
            $where_clause = $wpdb->prepare(" WHERE bidspirit_user_email = %s", $user);
        }
        
        $logs = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$table_name} {$where_clause} ORDER BY id DESC LIMIT %d OFFSET %d",
            $limit,
            $offset
        ));
        
        $total = $wpdb->get_var("SELECT COUNT(*) FROM {$table_name} {$where_clause}");
        
        $response = array(
            'success' => true,
            'data' => array(
                'logs' => $logs,
                'total' => intval($total),
                'limit' => $limit,
                'offset' => $offset,
                'has_more' => ($offset + $limit) < $total
            )
        );
        
        echo json_encode($response);
    }

    /**
     * Get Firebase users for debugging
     */
    public function firebase_users()
    {
        register_rest_route(self::API_NAMESPACE, '/firebase-users', array(
            'methods' => 'GET',
            'callback' => array($this, 'firebase_users_action'),
            'args' => array(
                'email' => array(
                    'type' => 'string',
                    'required' => false
                )
            ),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            }
        ));
    }

    /**
     * Get Firebase users action
     */
    public function firebase_users_action(WP_REST_Request $request)
    {
        global $wpdb;
        
        $params = $request->get_params();
        $email = $params['email'] ?? null;
        
        $table_name = $wpdb->prefix . 'firebase_users';
        
        if ($email) {
            $users = $wpdb->get_results($wpdb->prepare(
                "SELECT * FROM {$table_name} WHERE bidspirit_user_email = %s",
                $email
            ));
        } else {
            $users = $wpdb->get_results("SELECT * FROM {$table_name} ORDER BY id DESC LIMIT 50");
        }
        
        $response = array(
            'success' => true,
            'data' => array(
                'users' => $users,
                'count' => count($users)
            )
        );
        
        echo json_encode($response);
    }

    /**
     * Clear Firebase logs for testing
     */
    public function clear_firebase_logs()
    {
        register_rest_route(self::API_NAMESPACE, '/clear-firebase-logs', array(
            'methods' => 'POST',
            'callback' => array($this, 'clear_firebase_logs_action'),
            'args' => array(
                'days' => array(
                    'type' => 'integer',
                    'default' => 7,
                    'minimum' => 1,
                    'maximum' => 365
                ),
                'confirm' => array(
                    'type' => 'boolean',
                    'required' => true
                )
            ),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            }
        ));
    }

    /**
     * Clear Firebase logs action
     */
    public function clear_firebase_logs_action(WP_REST_Request $request)
    {
        global $wpdb;
        
        $params = $request->get_params();
        $days = $params['days'];
        $confirm = $params['confirm'];
        
        if (!$confirm) {
            echo json_encode(array(
                'success' => false,
                'message' => 'Confirmation required to clear logs'
            ));
            return;
        }
        
        $table_name = $wpdb->prefix . 'firebase_logs';
        
        $result = $wpdb->query($wpdb->prepare(
            "DELETE FROM {$table_name} WHERE created < DATE_SUB(NOW(), INTERVAL %d DAY)",
            $days
        ));
        
        $response = array(
            'success' => true,
            'message' => "Cleared {$result} log entries older than {$days} days",
            'deleted_count' => $result
        );
        
        echo json_encode($response);
    }

    /**
     * Get Firebase status and configuration
     */
    public function firebase_status()
    {
        register_rest_route(self::API_NAMESPACE, '/firebase-status', array(
            'methods' => 'GET',
            'callback' => array($this, 'firebase_status_action'),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            }
        ));
    }

    /**
     * Get Firebase status action
     */
    public function firebase_status_action(WP_REST_Request $request)
    {
        global $wpdb;
        
        $response = array(
            'success' => true,
            'data' => array()
        );
        
        try {
            // Check Firebase configuration
            $service_file_exists = file_exists(__DIR__.'/../services/service.php');
            $response['data']['service_file_exists'] = $service_file_exists;
            
            // Check if Firebase messaging is available
            $messaging_available = class_exists('Kreait\Firebase\Factory');
            $response['data']['messaging_available'] = $messaging_available;
            
            // Get users count
            $users_table = $wpdb->prefix . 'firebase_users';
            $users_count = $wpdb->get_var("SELECT COUNT(*) FROM {$users_table}");
            $response['data']['registered_users'] = intval($users_count);
            
            // Get logs count
            $logs_table = $wpdb->prefix . 'firebase_logs';
            $logs_count = $wpdb->get_var("SELECT COUNT(*) FROM {$logs_table}");
            $response['data']['total_logs'] = intval($logs_count);
            
            // Get recent logs count (last 24 hours)
            $recent_logs = $wpdb->get_var("SELECT COUNT(*) FROM {$logs_table} WHERE created >= DATE_SUB(NOW(), INTERVAL 24 HOUR)");
            $response['data']['recent_logs_24h'] = intval($recent_logs);
            
            // Get successful notifications count (last 24 hours)
            $successful_logs = $wpdb->get_var("SELECT COUNT(*) FROM {$logs_table} WHERE created >= DATE_SUB(NOW(), INTERVAL 24 HOUR) AND response_to_bidspirit LIKE '%\"success\":true%'");
            $response['data']['successful_notifications_24h'] = intval($successful_logs);
            
            // Calculate success rate
            if ($recent_logs > 0) {
                $response['data']['success_rate_24h'] = round(($successful_logs / $recent_logs) * 100, 2);
            } else {
                $response['data']['success_rate_24h'] = 0;
            }
            
            // Test Firebase connection
            try {
                $messaging = $this->getFactoryMessaging();
                $response['data']['firebase_connection'] = 'OK';
            } catch (Exception $e) {
                $response['data']['firebase_connection'] = 'ERROR: ' . $e->getMessage();
            }
            
        } catch (Exception $e) {
            $response['success'] = false;
            $response['error'] = $e->getMessage();
        }
        
        echo json_encode($response);
    }

    /**
     * Get Firebase status PUBLIC (без авторизации)
     */
    public function firebase_status_public()
    {
        register_rest_route(self::API_NAMESPACE, '/firebase-status-public', array(
            'methods' => 'GET',
            'callback' => array($this, 'firebase_status_public_action'),
            'args' => array(
                'testKey' => array(
                    'type' => 'string',
                    'required' => true,
                    'description' => 'Test key for security (use: test_firebase_2024)'
                )
            ),
            'permission_callback' => function ($request) {
                return true; // Публичный endpoint
            }
        ));
    }

    /**
     * Get Firebase status action PUBLIC
     */
    public function firebase_status_public_action(WP_REST_Request $request)
    {
        $params = $request->get_params();
        $testKey = $params['testKey'] ?? '';
        
        if ($testKey !== 'test_firebase_2024') {
            echo json_encode(array(
                'success' => false,
                'message' => 'Invalid test key. Use: test_firebase_2024'
            ));
            return;
        }

        global $wpdb;
        
        $response = array(
            'success' => true,
            'data' => array(),
            'note' => 'PUBLIC STATUS ENDPOINT - Только для отладки!'
        );
        
        try {
            // Check Firebase configuration
            $service_file_exists = file_exists(__DIR__.'/../services/service.php');
            $response['data']['service_file_exists'] = $service_file_exists;
            
            // Check if Firebase messaging is available
            $messaging_available = class_exists('Kreait\Firebase\Factory');
            $response['data']['messaging_available'] = $messaging_available;
            
            // Get users count
            $users_table = $wpdb->prefix . 'firebase_users';
            $users_count = $wpdb->get_var("SELECT COUNT(*) FROM {$users_table}");
            $response['data']['registered_users'] = intval($users_count);
            
            // Get logs count
            $logs_table = $wpdb->prefix . 'firebase_logs';
            $logs_count = $wpdb->get_var("SELECT COUNT(*) FROM {$logs_table}");
            $response['data']['total_logs'] = intval($logs_count);
            
            // Get recent logs count (last 24 hours)
            $recent_logs = $wpdb->get_var("SELECT COUNT(*) FROM {$logs_table} WHERE created >= DATE_SUB(NOW(), INTERVAL 24 HOUR)");
            $response['data']['recent_logs_24h'] = intval($recent_logs);
            
            // Get successful notifications count (last 24 hours)
            $successful_logs = $wpdb->get_var("SELECT COUNT(*) FROM {$logs_table} WHERE created >= DATE_SUB(NOW(), INTERVAL 24 HOUR) AND response_to_bidspirit LIKE '%\"success\":true%'");
            $response['data']['successful_notifications_24h'] = intval($successful_logs);
            
            // Calculate success rate
            if ($recent_logs > 0) {
                $response['data']['success_rate_24h'] = round(($successful_logs / $recent_logs) * 100, 2);
            } else {
                $response['data']['success_rate_24h'] = 0;
            }
            
            // Test Firebase connection
            try {
                $messaging = $this->getFactoryMessaging();
                $response['data']['firebase_connection'] = 'OK';
            } catch (Exception $e) {
                $response['data']['firebase_connection'] = 'ERROR: ' . $e->getMessage();
            }
            
        } catch (Exception $e) {
            $response['success'] = false;
            $response['error'] = $e->getMessage();
        }
        
        echo json_encode($response);
    }

    /**
     * Test Firebase connection and send a simple test message
     */
    public function test_firebase_connection()
    {
        register_rest_route(self::API_NAMESPACE, '/test-firebase-connection', array(
            'methods' => 'POST',
            'callback' => array($this, 'test_firebase_connection_action'),
            'permission_callback' => function ($request) {
                return $this->checkNoncePermission($request);
            }
        ));
    }

    /**
     * Test Firebase connection action
     */
    public function test_firebase_connection_action(WP_REST_Request $request)
    {
        $response = array(
            'success' => false,
            'message' => '',
            'tests' => array()
        );
        
        try {
            // Test 1: Check if Firebase classes are available
            $response['tests']['firebase_classes'] = class_exists('Kreait\Firebase\Factory');
            
            // Test 2: Check service file
            $service_file_path = __DIR__.'/../services/service.php';
            $response['tests']['service_file_exists'] = file_exists($service_file_path);
            
            // Test 3: Try to create Firebase factory
            try {
                $factory = $this->getFactoryMessaging();
                $response['tests']['factory_creation'] = true;
            } catch (Exception $e) {
                $response['tests']['factory_creation'] = false;
                $response['tests']['factory_error'] = $e->getMessage();
            }
            
            // Test 4: Check database tables
            global $wpdb;
            $users_table = $wpdb->prefix . 'firebase_users';
            $logs_table = $wpdb->prefix . 'firebase_logs';
            
            $users_table_exists = $wpdb->get_var("SHOW TABLES LIKE '{$users_table}'") === $users_table;
            $logs_table_exists = $wpdb->get_var("SHOW TABLES LIKE '{$logs_table}'") === $logs_table;
            
            $response['tests']['users_table_exists'] = $users_table_exists;
            $response['tests']['logs_table_exists'] = $logs_table_exists;
            
            // Overall success
            $response['success'] = $response['tests']['firebase_classes'] && 
                                   $response['tests']['service_file_exists'] && 
                                   $response['tests']['factory_creation'] && 
                                   $response['tests']['users_table_exists'] && 
                                   $response['tests']['logs_table_exists'];
            
            if ($response['success']) {
                $response['message'] = 'All Firebase tests passed successfully';
            } else {
                $response['message'] = 'Some Firebase tests failed. Check the tests object for details.';
            }
            
        } catch (Exception $e) {
            $response['success'] = false;
            $response['message'] = 'Error during Firebase connection test: ' . $e->getMessage();
        }
        
        echo json_encode($response);
    }

    /**
     * Handle large token batches asynchronously
     * For cases where we have hundreds/thousands of tokens
     */
    public function schedule_bulk_notifications($notificationType, $obj, $deviceTokens)
    {
        if (count($deviceTokens) <= 50) {
            // Use direct sending for small batches
            return false;
        }
        
        // Split tokens into chunks of 50
        $chunks = array_chunk($deviceTokens, 50);
        $scheduleTime = time();
        
        foreach ($chunks as $index => $chunk) {
            // Schedule each chunk with 30 second intervals
            $scheduleTime += 30;
            
            $hookName = 'auctionforge_send_firebase_chunk';
            $args = array(
                'notificationType' => $notificationType,
                'obj' => serialize($obj),
                'tokens' => $chunk,
                'chunk_index' => $index,
                'total_chunks' => count($chunks)
            );
            
            wp_schedule_single_event($scheduleTime, $hookName, array($args));
        }
        
        // Add the hook handler
        add_action('auctionforge_send_firebase_chunk', array($this, 'process_firebase_chunk'));
        
        return count($chunks);
    }
    
    /**
     * Process a single chunk of tokens
     */
    public function process_firebase_chunk($args)
    {
        $notificationType = $args['notificationType'];
        $obj = unserialize($args['obj']);
        $deviceTokens = $args['tokens'];

        // Log chunk processing start
        Debug::logData(array(
            'chunk' => $args['chunk_index'] + 1,
            'total_chunks' => $args['total_chunks'],
            'tokens' => count($deviceTokens),
            'type' => $notificationType
        ), 'firebase_bulk_processing');

        // Create test notification object and process
        try {
            $fbResponse = $this->processTestNotification($notificationType, $obj);

                        // Log only significant results
            $successCount = $fbResponse['response']['successCount'] ?? 0;
            $failureCount = $fbResponse['response']['failureCount'] ?? 0;
            
            if ($failureCount > 0 || $successCount > 0) {
                Debug::logData(array(
                    'chunk' => $args['chunk_index'] + 1,
                    'success' => $successCount,
                    'failed' => $failureCount,
                    'status' => $fbResponse['result'] ? 'completed' : 'partial'
                ), 'firebase_bulk_results');
            }
            
        } catch (Exception $e) {
            Debug::logData(array(
                'chunk' => $args['chunk_index'] + 1,
                'error' => $e->getMessage()
            ), 'firebase_bulk_errors');
        }
    }

    /**
     * Register PUBLIC endpoint for testing bulk push notifications
     */
    public function test_bulk_push()
    {
        if (!defined('ABSPATH')) {
            die('You shouldnt be here');
        }

        $namespace = self::API_NAMESPACE;

        $rout = '/test-bulk-push';

        $rout_params = array(
            'methods' => 'POST',
            'callback' => array($this, 'test_bulk_push_action'),
            'args' => array(
                'notificationType' => array(
                    'type' => 'string',
                    'required' => true,
                    'description' => 'Type of notification to test',
                    'enum' => array(
                        'LEADING_BID_SURPASSED',
                        'AUCTION_STARTS_SOON',
                        'ITEM_LIVE_SOON',
                        'AUCTION_PUBLISHED',
                        'CATALOG_PUBLISHED',
                        'ANNOUNCEMENT',
                        'TEST'
                    )
                ),
                'tokenCount' => array(
                    'type' => 'integer',
                    'required' => false,
                    'default' => 100,
                    'minimum' => 51,
                    'maximum' => 1000,
                    'description' => 'Number of fake tokens to generate for testing (51-1000)'
                ),
                'useAsync' => array(
                    'type' => 'boolean',
                    'required' => false,
                    'default' => false,
                    'description' => 'Use asynchronous processing for large batches'
                ),
                'testKey' => array(
                    'type' => 'string',
                    'required' => true,
                    'description' => 'Test key for security (use: test_firebase_2024)'
                )
            ),
            'permission_callback' => function ($request) {
                return true; // Public endpoint
            },
        );

        register_rest_route($namespace, $rout, $rout_params);
    }

    /**
     * Handle bulk test push notification request
     */
    public function test_bulk_push_action(WP_REST_Request $request)
    {
        $params = $request->get_params();
        $testKey = $params['testKey'] ?? '';
        
        if ($testKey !== 'test_firebase_2024') {
            echo json_encode(array(
                'success' => false,
                'message' => 'Invalid test key. Use: test_firebase_2024'
            ));
            return;
        }

        $notificationType = $params['notificationType'];
        $tokenCount = $params['tokenCount'] ?? 100;
        $useAsync = $params['useAsync'] ?? false;

        $response = array(
            'success' => false,
            'message' => '',
            'data' => array(),
            'params' => $params,
            'note' => 'BULK TESTING - Simulated tokens'
        );

        try {
            // Generate fake device tokens for testing
            $fakeTokens = array();
            for ($i = 0; $i < $tokenCount; $i++) {
                $fakeTokens[] = 'fake_token_' . $i . '_' . substr(md5(rand()), 0, 10);
            }
            
            // Create test notification object
            $obj = $this->createTestNotificationObject($notificationType, null, array());
            
            if ($useAsync && $tokenCount > 50) {
                // Use asynchronous processing
                $chunksScheduled = $this->schedule_bulk_notifications($notificationType, $obj, $fakeTokens);
                
                $response['success'] = true;
                $response['message'] = 'Bulk notification scheduled for asynchronous processing';
                $response['data'] = array(
                    'processing_method' => 'asynchronous',
                    'total_tokens' => $tokenCount,
                    'chunks_scheduled' => $chunksScheduled,
                    'estimated_completion_time' => date('Y-m-d H:i:s', time() + ($chunksScheduled * 30)),
                    'note' => 'Check debug logs for processing status'
                );
                
            } else {
                // Use direct processing (will be limited to 50 tokens)
                $response['data']['processing_method'] = 'direct_limited';
                $response['data']['original_token_count'] = $tokenCount;
                
                // This will automatically limit to 50 tokens and provide performance metrics
                $mockData = array('request' => array(
                    'notification' => array('title' => 'Bulk Test', 'body' => 'Testing bulk processing'),
                    'data' => array('notificationId' => 'bulk_test_' . time())
                ));
                
                $result = $this->sendMessage($mockData, $fakeTokens);
                
                $response['success'] = true;
                $response['message'] = 'Bulk test completed (limited to 50 tokens for direct processing)';
                $response['data']['result'] = $result;
            }
            
        } catch (Exception $e) {
            $response['success'] = false;
            $response['message'] = 'Error in bulk test: ' . $e->getMessage();
            $response['error'] = $e->getMessage();
        }

        echo json_encode($response);
    }
}

// Initialize the class
$instance = new AuctionsAPI();
$instance->init();

// Initialize test helpers (only in development/testing environment)
if (defined('WP_DEBUG') && WP_DEBUG) {
    $instance->init_test_helpers();
    add_action('rest_api_init', array($instance, 'test_firebase_connection'));
}
