func DB.GetUserIdFromSession(session)
{
    DB.Lock();
    var dbCon = DB.Open();
    var exec = Sqlite.Exec(dbCon,$"SELECT * FROM sessions WHERE key = {Sqlite.Escape(session)};");
   
   
    
    if(TypeOf(exec) == "List" && exec.Length == 1) 
    { 
        var expiry = 0;
        const expires = ParseLong(exec[0].expires);
        if(TypeIsLong(expires) && expires != 0)
        {
            const whenItExpires =  ParseLong(expires);
			const currentTime = DateTime.NowEpoch ?? 0;
            if(whenItExpires != 0 && currentTime < whenItExpires && (whenItExpires - currentTime) < (DB.Expires-3600))
			{
				expiry = currentTime + DB.Expires;
				Sqlite.Exec(dbCon, $"UPDATE sessions SET expires = {expiry} WHERE key = {Sqlite.Escape(session)};");
			}
			else if(whenItExpires != 0 && currentTime >= whenItExpires)
			{
				Sqlite.Exec(dbCon, $"DELETE FROM sessions WHERE key = {Sqlite.Escape(session)};");
                Sqlite.Close(dbCon);
                DB.Unlock();      
                return null;              
			}

        }
        Sqlite.Close(dbCon);
        DB.Unlock();  
        return { accountId =  ParseLong(exec[0].accountId), expiry };
    }
    Sqlite.Close(dbCon);
    DB.Unlock();  
    return null;
}
func DB.GetSessionFromBearer(ctx)
{
    var auth = ctx.RequestHeaders.TryGetFirst("Authorization");
    if(TypeOf(auth) == "String")
    {
        auth=auth.Split(" ",true,2);
        if(auth.Length < 2) return null;
        if(auth[0] != "Bearer") return null;
        var uid = DB.GetUserIdFromSession(auth[1]);
        if(TypeIsDictionary(uid)) return auth[1];
    }
    return null;
}
func DB.GetSession(ctx)
{
    var cookie = ctx.RequestHeaders.TryGetFirst("Cookie");
    if(TypeOf(cookie) == "String")
    {
        each(var part : cookie.Split("; "))
        {
            if(part.Length > 0)
            {
                var cookieKV = part.Split("=",true,2);
                if(cookieKV.Length == 2 && cookieKV[0] == "Session")
                {
                    var session = cookieKV[1];
                    var sessionObj = DB.GetUserIdFromSession(session);
                    
                    if(TypeIsDictionary(sessionObj))
                    {
                        if(sessionObj.expiry > 0)
                        {
                            ctx.WithHeader("Set-Cookie",$"Session={session}; SameSite=Lax; Expires={new DateTime(sessionObj.expiry).ToHttpDate()}");
                        }

                        return session;
                    }
                }
            }
        }
    }
    return null;
}
func DB.CreateSession(userId, doesExpire, name)
{
    const now = DateTime.NowEpoch;
    const expiryTime = doesExpire ? (DB.Expires + now) : 0; 


    DB.Lock();
    var dbCon = DB.Open();
  
    var rand = Net.Http.UrlEncode(Crypto.Base64Encode(Crypto.RandomBytes(32, "CPKG")));
    Sqlite.Exec(dbCon,$"INSERT INTO sessions (accountId,key, expires, created, name) VALUES ({userId},{Sqlite.Escape(rand)},{Sqlite.Escape(expiryTime)},{Sqlite.Escape(now)}, {Sqlite.Escape(name)});");
    Sqlite.Close(dbCon);
    DB.Unlock();
    return rand;
}
func DB.DestroySession(session)
{
    if(TypeOf(session) != "String") return false;
    DB.Lock();
    var dbCon = DB.Open();
    var res = Sqlite.Exec(dbCon, $"DELETE FROM sessions WHERE key = {Sqlite.Escape(session)};");
    Sqlite.Close(dbCon);
    DB.Unlock();
    if(TypeOf(res) == "String") return false;

    return true;
}