<?php

namespace Api\PhpServices\Session;

use Api\PhpServices\Session\RedisSession;

class SessionManager
{
    /**
     * get session instance
     * @return RedisSession
     */
    public static function getSession()
    {
        return RedisSession::getInstance();
    }

    /**
     * set session app
     * @param string $app
     * @return boolean
     */
    public static function setAppid($app)
    {
        self::getSession()->setAppid($app);
        return true;
    }

    /**
     * get session app
     * @return string
     */
    public static function getAppid()
    {
        return self::getSession()->getAppid();
    }

    /**
     * get session name
     * @return string
     */
    public static function name()
    {
        return self::getSession()->getSessionName();
    }

    /**
     * get session id
     * @return string
     */
    public static function sid()
    {
        return self::getSession()->getSessionId();
    }

    /**
     * whether session started
     * @return boolean
     */
    public static function started()
    {
        return self::getSession()->started();
    }

    /**
     * 删除非访客session
     *
     * @param int $userid
     * @param string $username
     * @param string $app
     * @return bool
     */
    public static function delete_nonguest($appid, $userid)
    {
        $session = self::getSession();
        return $session->deleteByUser($appid, $userid, 2);
    }

    /**
     * delete all sessions of the user
     * @param integer $userid
     * @param string $username
     * @param string $app
     * @return boolean
     */
    public static function delete_all($appid, $userid)
    {
        $session = self::getSession();
        return $session->deleteByUser($appid, $userid);
    }

    /**
     * delete sessions
     * @param array|string $sessionIds
     * @return boolean
     */
    public static function delete($sessionIds)
    {
        return self::getSession()->delete($sessionIds);
    }

    /**
     * destroy session
     * @return boolean
     */
    public static function destroy()
    {
        $session = self::getSession();
        if (!self::started()) {
            $sessionId = $_COOKIE[$session->getSessionName()] ?? '';
            if (empty($sessionId) || !$session->checkSessionId($sessionId)) {
                return false;
            }
            return $session->delete($sessionId);
        }
        if ($session->destroy()) {
            $_SESSION = [];
            return true;
        }
        return false;
    }

    /**
     * start session from cookie
     * @param boolean $readOnly     是否只读会话
     *                              以只读形式打开的会话，如果session发生了更改，需要手动调用write()写入会话
     * @param string $app
     * @return RedisSession
     */
    public static function start($readOnly = true)
    {
        $session = self::getSession();
        if ($session->start($readOnly)) {
            if (!empty($_SESSION)
                && (!isset($_SESSION['utime']) || (time() - $_SESSION['utime']) > 86400)) {
                $_SESSION['utime'] = time();
                self::write();
            }
            return $session;
        }
        return false;
    }

    /**
     * set session
     * @param array $session
     * @param boolean $readonly
     * @param integer $cookieExpire
     * @return boolean
     */
    public static function set($appid, $userid, $isLogin, array $session, $maxLogin = 10, $cookieExpire = 0)
    {
        // 只允许单台设备登录,先清除所有已登录用户的sessionid
        if ($isLogin && $maxLogin === 1) {
            self::delete_nonguest($appid, $userid);
        }
        // @todo 大于1小于10, 让用户选择需要下线的设备信息，暂无此需求
        
        $sessionInstance = self::getSession();
        if (!$sessionInstance->create($appid, $userid, $isLogin)) {
            return false;
            // throw new \Exception('session was not started');
        }
        self::fillup($session);
        self::write();
        $sessionInstance->setCookie($cookieExpire);
        return $sessionInstance->getSessionName() . '=' . $sessionInstance->getSessionId();
    }

    /**
     * fillup $_SESSION
     * @param array $session
     * @param boolean $readonly
     * @return array
     */
    public static function fillup(array $session)
    {
        $_SESSION['utime'] = time();
        foreach ($session as $key => $value) {
            $_SESSION[$key] = $value;
        }

        return $_SESSION;
    }

    /**
     * read session data
     * @return array
     */
    public static function read()
    {
        self::pickup();
        if (!empty($_SESSION)
            && (!isset($_SESSION['utime']) || (time() - $_SESSION['utime']) > 86400)) {
            $_SESSION['utime'] = time();
            if (self::started()) {
                self::write();
            } else {
                self::close();
            }
        }

        return $_SESSION;
    }

    /**
     * pickup data from session
     */
    public static function pickup()
    {
        if (!empty($_SESSION['userid'])) {
            $_GET['userid'] = $_SESSION['userid'];
            $_POST['userid'] = $_SESSION['userid'];
            $_REQUEST['userid'] = $_SESSION['userid'];
        }

        if (!isset($_GET['version']) && isset($_SESSION['version'])) {
            $_GET['version'] = $_SESSION['version'];
        }

        if (isset($_SESSION['usertype'])) {
            $_GET['usertype'] = $_SESSION['usertype'];
        }

        if (isset($_SESSION['readonly'])) {
            $_GET['readonly'] = $_SESSION['readonly'];
        }
    }

    /**
     * get session data
     * @return array
     */
    public static function get()
    {
        return $_SESSION;
    }

    /**
     * write session data
     * @return boolean
     */
    public static function write()
    {
        return self::getSession()->write();
    }

    /**
     * close session
     * @return boolean
     */
    public static function close()
    {
        return self::getSession()->close();
    }
}
