<?php

namespace Application\Service\Extension\Helper;

use Application\Command\Swoole\Server\WebSocketCommand;
use Application\Service\Extension\Laminas;
use GuzzleHttp\Psr7\Request;
use Swoole\Coroutine;
use Swoole\Coroutine\Http\Client;
use function Co\run;

/**
 * 小程序ws推送
 */
class WsHelper
{
    /** @var int 质疑沟通 */
    public const MODULE_QUESTION = 60;

    private const QUESTION_KEY = 'ws:question:';

    /** @var int AE */
    public const MODULE_AE = 58;

    /** @var int 工作清单 */
    public const MODULE_LIST_SET = 79;

    private const AE_KEY = 'ws:ae:';

    private const LIST_SET_KEY = 'ws:listSet:';

    /**
     * @return mixed|\Redis
     */
    private static function getRedis()
    {
        return Laminas::$serviceManager->redisExtend->setDatabase(6)->getRedisInstance();
    }


    /**
     * 推送质疑沟通提醒
     * @param int $signId 中心id
     */
    public static function pushQuestionMessage(int $itemId, int $signId)
    {
        $user = self::getQuestionUser($signId);

        $signUserId = array_filter(array_unique(self::getSignUser($signId)));

        if(!empty($signUserId)){
            foreach ($signUserId as $item) {
                if ($item) {
                    $redisKey = self::QUESTION_KEY . $itemId . $item;
                    $allSign = array_unique(ArrayHelper::getColumn(Laminas::$serviceManager->roleSignatoryRelation->fetchAll([
                        'where' => ['signatory_user' => $item]
                    ]), 'item_sign_id'));
                    $tmp= [];
                    if (!self::getRedis()->exists($redisKey)) {
                        foreach ($allSign as $sign) {
                            $tmp[$sign] = intval($sign == $signId);
                        }

                    } else {
                        foreach ($allSign as $sign) {
                            if ($sign == $signId) {
                                $tmp[$sign] = 1;
                            }
                        }
                    }
                    self::getRedis()->hMSet($redisKey, $tmp);
                }
            }
        }
        if(!empty($user)){
            self::addMessage(self::MODULE_QUESTION, $user, $itemId);
        }
    }

    /**
     * 移除质疑沟通提醒
     * @param int $signId 中心id
     */
    public static function flushQuestionMessage(int $itemId, int $signId)
    {
        $signUserId = array_unique(self::getSignUser($signId));
        $hasQuestion = null;
        $pushUserArr = [];

        foreach ($signUserId as $item) {
            $isDel = 1;
            $redisKey = self::QUESTION_KEY . "{$itemId}:{$item}";
            $signMap = self::getRedis()->hGetAll($redisKey) ?: [];
            $pushUserArr[] = $item;
            $isPop = false;

            foreach ($signMap as $sign => $status) {
                if ($sign == $signId) {
                    if ($hasQuestion === null) {
                        $hasQuestion = self::hasQuestion($signId, $itemId);
                    }

                    if (!$hasQuestion) {
                        self::getRedis()->hMSet($redisKey, [
                            $sign => 0
                        ]);
                    } else {
                        $isDel = 0;
                        if ($isPop === false) {
                            array_pop($pushUserArr);
                            $isPop = true;
                        }
                    }
                } else {
                    if ($status == 1) {
                        $isDel = 0;
                        if ($isPop === false) {
                            array_pop($pushUserArr);
                            $isPop = true;
                        }
                    }
                }
            }

            if ($isDel == 1) {
                self::getRedis()->del($redisKey);
            }
        }

        if ($pushUserArr) {
            $user = self::getQuestionUser($signId, $pushUserArr);
            self::flushMessage(self::MODULE_QUESTION, $user, $itemId);
            self::publish($user, $itemId);
        }
    }

    public static function pushAeMessage(int $itemId, $signId)
    {
        $userSigData = self::getSignUserData($signId);
        $userSigDatas = [];
        $signUserId = [];
        foreach ($userSigData as $userSigDataKey =>$userSigDataValue){
            if (isset($userSigDatas[$userSigDataValue['signatory_user']])){
                $userSigDatas[$userSigDataValue['signatory_user']][] = $userSigDataValue['item_sign_id'];
                if (!isset($signUserId[$userSigDataValue['signatory_user']])){
                    $signUserId[] = $userSigDataValue['signatory_user'];
                }
            }else{
                $userSigDatas[$userSigDataValue['signatory_user']][] = $userSigDataValue['item_sign_id'];
                $signUserId[] = $userSigDataValue['signatory_user'];

            }
        }
        $user = self::getQuestionUser($signId,$signUserId);

        if (!empty($userSigDatas)){
            foreach ($userSigDatas as $userSigDatasKey=>$userSigDatasValue) {
                $redisKey = self::AE_KEY . "{$itemId}:{$userSigDatasKey}";
                $allSign = array_filter(array_unique($userSigDatasValue));
                $tmp= [];
                if (!self::getRedis()->exists($redisKey)) {

                    foreach ($allSign as $sign) {
                        $tmp[$sign] = intval($sign == $signId);
                    }
                } else {
                    foreach ($allSign as $sign) {
                        if ($sign == $signId) {
                            $tmp[$sign] = 1;
                        }
                    }
                }
                self::getRedis()->hMSet($redisKey, $tmp);
            }
        }
        self::addMessage(self::MODULE_AE, $user, $itemId);
    }

    /**
     * 推送工作清单
     * @param int $itemId
     * @param $signId
     * @param string $role
     */
    public static function pushListSetMessage(int $itemId, $signId, string $role = '')
    {
        if (!$itemId) {
            return;
        }

        $role = $role ? explode(',', $role) : [];
        if (!empty($role)) {
            $signUserId = array_unique(self::getSignUser($signId, [
                'role_id' => $role
            ]));
        } else {
            $signUserId = array_unique(self::getSignUser($signId));
        }
        $user = !empty($role) ? self::getListSetUser($role, $signId) : [];
        if(!empty($signUserId)){
            foreach ($signUserId as $item) {
                if ($item) {
                    $redisKey = self::LIST_SET_KEY . "{$itemId}:{$item}";
                    $allSign = array_unique(ArrayHelper::getColumn(Laminas::$serviceManager->roleSignatoryRelation->fetchAll([
                        'where' => ['signatory_user' => $item]
                    ]), 'item_sign_id'));
                    $tmp = [];
                    if (!self::getRedis()->exists($redisKey)) {
                        foreach ($allSign as $sign) {
                            $tmp[$sign] = intval($sign == $signId);
                        }

                    } else {
                        foreach ($allSign as $sign) {
                            if ($sign == $signId) {
                                $tmp[$sign] = 1;
                            }
                        }
                    }
                    self::getRedis()->hMSet($redisKey, $tmp);
                }
            }
        }
        if(!empty($user)) {
            self::addMessage(self::MODULE_LIST_SET, $user, $itemId);
        }
    }

    /**
     * 获取工作清单发送用户列表
     * @param array $role
     * @param $signId
     * @return array
     */
    public static function getListSetUser(array $role, $signId): array
    {
        $user = ArrayHelper::getColumn(Laminas::$serviceManager->roleSignatoryRelation->fetchAll([
            'where' => [
                'role_id' => $role,
                'item_sign_id' => $signId,
                'status' => 0
            ]
        ]), 'signatory_user');

        $tel = ArrayHelper::getColumn(Laminas::$serviceManager->signatoryUser->fetchAll([
            'where' => ['id' => $user, ]
        ]), 'user_tel');

        return ArrayHelper::getColumn(Laminas::$serviceManager->adminUser->fetchAll([
            'where' => ['mobile' => $tel, 'is_del' => 0]
        ]), 'id');
    }

    public static function flushAeMessage(int $itemId, int $signId)
    {
        $signUserId = array_unique(self::getSignUser($signId));
        $hasAe = null;
        $pushUserArr = [];
        foreach ($signUserId as $item) {
            $isDel = 1;
            $redisKey = self::AE_KEY . "{$itemId}:{$item}";
            $signMap = self::getRedis()->hGetAll($redisKey) ?: [];
            $pushUserArr[] = $item;
            $isPop = false;

            foreach ($signMap as $sign => $status) {
                if ($sign == $signId) {
                    if ($hasAe === null) {
                        $hasAe = self::hasAe($signId, $itemId);
                    }

                    if (!$hasAe) {
                        self::getRedis()->hMSet($redisKey, [
                            $sign => 0
                        ]);
                    } else {
                        $isDel = 0;
                        if ($isPop === false) {
                            array_pop($pushUserArr);
                            $isPop = true;
                        }
                    }
                } else {
                    if ($status == 1) {
                        $isDel = 0;
                        if ($isPop === false) {
                            array_pop($pushUserArr);
                            $isPop = true;
                        }
//                        break;
                    }
                }
            }

            if ($isDel == 1) {
                self::getRedis()->del($redisKey);
            }
        }

        if ($pushUserArr) {
            $user = self::getQuestionUser($signId, $pushUserArr);
            self::flushMessage(self::MODULE_AE, $user, $itemId);
            self::publish($user, $itemId);
        }
    }

    public static function flushListSetMessage(int $itemId, int $signId, $role = '')
    {
        $role = $role ? explode(',', $role) : [];
        $signUserId = [];
        if (!empty($role)) {
            $signUserId = array_filter(array_unique(self::getSignUser($signId, [
                'role_id' => $role
            ])));
        } else {
            $signUserId = array_filter(array_unique(self::getSignUser($signId)));
        }

        $hasListSet = null;
        $pushUserArr = [];

        if(!empty($signUserId)){
            foreach ($signUserId as $item) {
                $isDel = 1;
                $redisKey = self::LIST_SET_KEY . "{$itemId}:{$item}";
                $signMap = self::getRedis()->hGetAll($redisKey) ?: [];
                $pushUserArr[] = $item;
                $isPop = false;
                if(!empty($signMap)){
                    foreach ($signMap as $sign => $status) {
                        if ($sign == $signId) {
                            if ($hasListSet === null) {
                                $hasListSet = self::hasListSet($signId, $role);
                            }

                            if (!$hasListSet) {
                                self::getRedis()->hMSet($redisKey, [
                                    $sign => 0
                                ]);
                            } else {
                                $isDel = 0;
                                if ($isPop === false) {
                                    array_pop($pushUserArr);
                                    $isPop = true;
                                }
                            }
                        } else {
                            if ($status == 1) {
                                $isDel = 0;
                                if ($isPop === false) {
                                    array_pop($pushUserArr);
                                    $isPop = true;
                                }
                            }
                        }
                    }
                }

                if ($isDel == 1) {
                    self::getRedis()->del($redisKey);
                }
            }
        }

        if ($pushUserArr) {
            $user = self::getQuestionUser($signId, $pushUserArr);
            self::flushMessage(self::MODULE_LIST_SET, $user, $itemId);
            if(!empty($user)){
                self::publish($user, $itemId);
            }
        }
    }

    public static function hasQuestion($signId, $itemId): bool
    {
        return (bool)Laminas::$serviceManager->itemQuestion->fetchAll([
            'columns' => ['id'],
            'where' => [
                'question_status' => 0,
                'is_del' => 0,
                'item_sign_id' => $signId,
                'item_id' => $itemId
            ]
        ]);
    }

    public static function hasAe($signId, $itemId): bool
    {
        return (bool)Laminas::$serviceManager->itemCsae->fetchAll([
            'columns' => ['id'],
            'where' => [
                'ae_type' => 0,
                'is_del' => 0,
                'itemsig_id' => $signId,
                'item_id' => $itemId
            ]
        ]);
    }

    private static function hasListSet($signId, $removeRole): bool
    {
        $hasListSet = Laminas::$serviceManager->listsetSiglist->fetchAll([
            'columns' => ['id'],
            'where' => [
                'is_del' => 0,
                'itemsig_id' => $signId,
                'flow_state' => [2, 3]
            ]
        ]) ?? [];

        foreach ($hasListSet as $item) {
            $flow = explode(',', $item['flow_role']);
            foreach ($removeRole as $role) {
                if (in_array($role, $flow)) {
                    return true;
                }
            }
        }

        return false;
    }



    /**
     * @param $signId
     * @param array $condition
     * @return array
     */
    private static function getSignUserData($signId): array
    {
        $where = [
            'item_sign_id' => $signId,
            'status' => 0
        ];
        return Laminas::$serviceManager->roleSignatoryRelation->fetchAll([
            'where' => $where,
            'columns'=>['signatory_user','item_sign_id'],
        ]);
    }

    /**
     * @param $signId
     * @param array $condition
     * @return array
     */
    private static function getSignUser($signId, array $condition = []): array
    {
        $where = [];

        if ($condition) {
            $where = ArrayHelper::merge([
                'item_sign_id' => $signId,
                'status' => 0
            ], $condition);
        }

        return ArrayHelper::getColumn(Laminas::$serviceManager->roleSignatoryRelation->fetchAll([
            'where' => $where
        ]), 'signatory_user');
    }
    /**
     * 获取所有可以看到此中心的用户
     * @param int $signId
     * @param array $pushUser
     * @return array
     */
    private static function getQuestionUserData(int $signId, array $pushUser = []): array
    {
        $tel = ArrayHelper::getColumn(Laminas::$serviceManager->signatoryUser->fetchAll([
            'where' => ['id' => $pushUser ?: self::getSignUser($signId)]
        ]), 'user_tel');
        return ArrayHelper::getColumn(Laminas::$serviceManager->adminUser->fetchAll([
            'where' => ['mobile' => $tel, 'is_del' => 0]
        ]), 'id');
    }

    /**
     * 获取所有可以看到此中心的用户
     * @param int $signId
     * @param array $pushUser
     * @return array
     */
    private static function getQuestionUser(int $signId, array $pushUser = []): array
    {
        if(empty($pushUser)){
            $pushUser = [0];
        }
        $tel = ArrayHelper::getColumn(Laminas::$serviceManager->signatoryUser->fetchAll([
            'where' => ['id' => $pushUser],
        ]), 'user_tel');
        return ArrayHelper::getColumn(Laminas::$serviceManager->adminUser->fetchAll([
            'where' => ['mobile' => $tel, 'is_del' => 0]
        ]), 'id');
    }

    /**
     * @param int $menuId 菜单id
     * @param int|array $userId 用户id
     */
    public static function addMessage(int $menuId, $userId, $itemId): bool
    {
        try {
            $userId = (array)$userId;
            foreach ($userId as $id) {
                Laminas::$serviceManager->redisExtend->setDatabase(6)->getRedisInstance()->setBit("menu:{$itemId}:{$menuId}", intval($id), 1);
            }

            self::publish($userId, $itemId);

            return true;
        }catch (\Throwable $exception) {
            var_dump([
                'type' => get_class($exception),
                'file' => method_exists($exception, 'getFile') ? $exception->getFile() : '',
                'errorMessage' => $exception->getMessage(),
                'executeSql' => method_exists($exception, 'getExecuteSql') ? $exception->getExecuteSql() : null,
                'line' => $exception->getLine(),
                'stack-trace' => explode("\n", $exception->getTraceAsString()),
            ]);
            return false;
        }

    }

    private static function flushMessage(int $menuId, $userId, $itemId): bool
    {
        $userId = (array)$userId;
        foreach ($userId as $id) {
            Laminas::$serviceManager->redisExtend->setDatabase(6)->getRedisInstance()->setBit("menu:{$itemId}:{$menuId}", $id, 0);
        }

        return true;
    }

    private static function publish($userId, $itemId)
    {
        $curl = curl_init();
        curl_setopt_array($curl, array(
            CURLOPT_URL => "https://{$_SERVER['HTTP_HOST']}:9502",
            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 => 'data=%7B%22action%22%3A%22publish%22%2C%20%22to%22%3A%22' . urlencode(implode(',', $userId)) . "%22%2C%22item_id%22%3A%22{$itemId}%22%7D",
            CURLOPT_HTTPHEADER => array(
                'Content-Type: application/x-www-form-urlencoded'
            ),
        ));

        $response = curl_exec($curl);

        curl_close($curl);
    }
}
