<?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\ImageModel;
use auctionforge\inc\Debug;
use auctionforge\inc\helpers\LotHelper;
use auctionforge\inc\helpers\SettingsHelper;
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\LotImage;
use WP_REST_Request;

/**
 * @Depricated
 * Use: Auctions App /test-push
 */
class TestAppNotification
{
    const APP_FIREBASE_COOKIE = 'FCM_TOKEN';
    const API_NAMESPACE = 'bidspirit/v1';

    public function init()
    {
        add_action('rest_api_init', array($this, 'notice'));
    }

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

        $namespace = self::API_NAMESPACE;
        $rout = '/user/notice';

        $rout_params = array(
            'methods' => 'POST',
            'callback' => array($this, 'notice_action'),
            'args' => array(
                'bidspirit_users' => array(
                    'type' => 'array',
                    'required' => true
                ),
                'title' => array(
                    'type' => 'string',
                    'required' => true
                ),
                'body' => array(
                    'type' => 'string',
                    'required' => true
                ),
            ),
            'permission_callback' => function ($request) {
                return $this->checkPermission();
            },
        );

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

    public function notice_action_leading_bid_surpassed(WP_REST_Request $request)
    {
        /** @var LeadingBidSurpassed $obj */
        $obj = new stdClass();
        $logs = [];

        $obj->auctionId = $request['auction_id'];
        $obj->auctionNumber = $request['auction_number'];
        $obj->user = $request['bidspirit_users'][0];
        $obj->itemId = $request['item_id'];
        $obj->itemName = $request['item_name'];
        $obj->itemIndex = $request['item_index'];
        $obj->lang = "en";
        $obj->notificationType = "LEADING_BID_SURPASSED";

        $data = $this->leading_bid_surpassed($obj);

        return array(
            'request' => $request->get_params(),
            'data' => $data,
            'log' => $logs
        );
    }

    public function notice_action_2(WP_REST_Request $request)
    {
        /** @var ItemLiveSoon $obj */
        $obj = new stdClass();
        $logs = [];

        $obj->auctionId = $request['auction_id'];
        $obj->auctionNumber = $request['auction_number'];
        $obj->users = $request['bidspirit_users'];
        $obj->itemId = $request['item_id'];
        $obj->itemName = $request['item_name'];
        $obj->itemIndex = $request['item_index'];
        $obj->lang = "en";
        $obj->notificationType = "ITEM_LIVE_SOON";

        $data = $this->item_live_soon($obj);

        return array(
            'request' => $request->get_params(),
            'data' => $data,
            'log' => $logs
        );
    }

    public function notice_action_auction_starts_soon(WP_REST_Request $request)
    {
        /** @var AuctionStartsSoon $obj */
        $obj = new stdClass();
        $logs = [];

        $obj->dayIndex = $request['day_index'];
        $obj->auctionId = $request['auction_id'];
        $obj->auctionNumber = $request['auction_number'];
        $obj->users = $request['bidspirit_users'];
        $obj->auctionName = $request['auction_name'];
        $obj->lang = "en";
        $obj->notificationType = "AUCTION_STARTS_SOON";

        $data = $this->auction_starts_soon($obj);

        return array(
            'request' => $request->get_params(),
            'data' => $data,
            'log' => $logs
        );
    }

    public function notice_action(WP_REST_Request $request)
    {
        if (!defined('AUCTIONFORGE_SERVICE_PACK')) {
            define('AUCTIONFORGE_SERVICE_PACK', 'service');
        }

        $service = require_once __DIR__.'/../services/' . AUCTIONFORGE_SERVICE_PACK . '.php';

        $data = $request->get_params();
        $deviceTokens = FirebaseUser::deviceTokensForUsers($data['bidspirit_users']);
        $imageUrl = (!empty($data['image'])) ? $data['image'] : 'https://bidspirit-images.global.ssl.fastly.net/web2-qa/cloned-images/17516/001/a_ignore_q_80_w_400_h_400_c_fit_001.jpg';

        $factory = (new Factory)->withServiceAccount($service);
        $messaging = $factory->createMessaging();

        if (empty($deviceTokens)) {
            return [
                'request' => $request->get_params(),
                'log' => 'Tokens not found'
            ];
        }

        try {
            $testTokens = $messaging->validateRegistrationTokens($deviceTokens);
            $logs['testTokens']['send'] = $testTokens;
        } catch (MessagingException $e) {
            $logs['testTokens']['MessagingException'] = $e->getMessage();
        } catch (FirebaseException $e) {
            $logs['testTokens']['MessagingException'] = $e->getMessage();
        }

        $url = !empty($data['url']) ? $data['url'] : '';
        $args = array(
            'token' => $deviceTokens[0],
            'notification' => array(
                'title' => $data['title'],
                'body' => $data['body'],
                'image' => $imageUrl,
                'imageUrl' => $imageUrl,
            ),
            'data' => array(
                'url' => $url,
                'image' => $imageUrl
            )
        );

        $message = CloudMessage::fromArray($args);

        try {
            $res = $messaging->send($message);
            $logs['result']['send'] = $res;
        } catch (MessagingException $e) {
            $logs['result']['MessagingException'] = $e->getMessage();
        } catch (FirebaseException $e) {
            $logs['result']['FirebaseException'] = $e->getMessage();
        }

        return array(
            'request' => $request->get_params(),
            'args' => $args,
            'log' => $logs
        );
    }

    /**
     * @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()) {
            $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' => get_permalink($postId),
                    'notificationId' => $obj->itemId . rand(111, 999)
                )
            );

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

        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)) {
            $data["request"] = array(
                'notification' => array(
                    'title' => $obj->auctionNumber . "/" . $obj->itemIndex . " " . __("item live soon", "auctionforge"),
                    'body' => $obj->itemName,
                    'image' => $this->getFeatureImageByLotId($postId)
                ),
                'data' => array(
                    'url' => get_permalink($postId),
                    'notificationId' => $obj->itemId . rand(111, 999)
                )
            );

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

        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)) {
            $data["request"] = array(
                'notification' => array(
                    'title' => $obj->auctionNumber . " " . __("auction starts soon", "auctionforge"),
                    'body' => $obj->auctionName,
                    'image' => $this->getFeatureImageByAuctionId($obj, $termId)
                ),
                'data' => array(
                    'url' => get_term_link($termId),
                    'notificationId' => $obj->auctionId
                )
            );

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

        return $data;
    }

    private function sendMessage($data, $deviceTokens = array())
    {
        $messaging = $this->getFactoryMessaging();
        $message = CloudMessage::fromArray($data["request"])->withDefaultSounds();
        try {
            if (!empty($deviceTokens)) {
                $validTokens = $messaging->validateRegistrationTokens($deviceTokens);
                if (!empty($validTokens["valid"])) {
                    $data["response"] = $messaging->sendMulticast($message, $validTokens["valid"]);
                }
            } else {
                $data["response"] = $messaging->send($message);
            }
        } catch (MessagingException $e) {
            $data["response"]["MessagingException"] = $e->getMessage();
            $data["result"] = false;
        } catch (FirebaseException $e) {
            $data["response"]["FirebaseException"] = $e->getMessage();
            $data["result"] = false;
        }
        return $data;
    }

    /**
     * @param $obj stdClass
     * @return array
     */
    private function test($obj)
    {
        //
        return array();
    }

    private function checkPermission()
    {
        $authToken = SettingsHelper::getOption('auth_token', '');
        return ($authToken != "" || defined('AUCTIONFORGE_API_TOKEN'));
    }

    /**
     * @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' => $obj->user,
            'bidspirit_lot_id' => $obj->itemIndex,
            'request_from_bidspirit' => $requestBody,
            'request_to_firebase' => $fbResponse["request"],
            'response_from_firebase' => $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::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)
    {
        $lotImages = new LotImage($postId);
        $images = $lotImages->getImageList();

        if (!empty($images[0])) {
            $featureImage = $images[0][ImageModel::LABEL_MEDIUM];
        } else {
            $featureImage = null;
        }
        return $featureImage;
    }

    /**
     * @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;
    }
}
$instance = new TestAppNotification();
$instance->init();
