-- Не отправлять атрибут SameSite=None известным несовместимым клиентам
-- https://www.chromium.org/updates/same-site/incompatible-clients
function shouldSendSameSiteNone(useragent)
    return not isSameSiteNoneIncompatible(useragent)
end

-- группы несвоместиых клиентов
function isSameSiteNoneIncompatible(useragent)
    return hasWebKitSameSiteBug(useragent) or dropsUnrecognizedSameSiteCookies(useragent)
end

-- относится ли клиент к группе, у которой есть баг при обработке SameSite=None
-- к ним относятся версии Safari и встроенных браузеров на MacOS 10.14 и все ьраузеры на iOS 12
-- баг заключается в том, что эти клиенты обращаеются с атрибутом SameSite=None как будто он Strict
function hasWebKitSameSiteBug(useragent)
    return isIosVersion(12, useragent) or
            (isMacosxVersion(10, 14, useragent) and (isSafari(useragent) or isMacEmbeddedBrowser(useragent)))
end

-- относится ли клиент к группе, которая отклоняет куки с SameSite=None
-- к ним относятся версии Chrome(c 51 по 66 включительно) и версии UC Browser(до версии 12.13.2) на Android
function dropsUnrecognizedSameSiteCookies(useragent)
    if isUcBrowser(useragent) then
        return not isUcBrowserVersionAtLeast(12, 13, 2, useragent)
    end
    return isChromiumBased(useragent) and
            isChromiumVersionAtLeast(51, useragent) and
            not isChromiumVersionAtLeast(67, useragent)
end

-- следующие функции определяют, относится useragent к определенному подклассу
-- проверка осуществляется с помощью регулярный выражений

-- iOS версии <major>
function isIosVersion(major, useragent)
    local major_version =  string.match(useragent, "%(iP.+; CPU .*OS (%d+)[_%d]*.*%) AppleWebKit%/")
    if tonumber(major_version) == major then
        return true
    end
    return false
end

-- MacOS версии <major>.<minor>
function isMacosxVersion(major, minor, useragent)
    local major_version, minor_version =  string.match(useragent, "%(Macintosh;.*Mac OS X (%d+)_(%d+)[_%d]*.*%) AppleWebKit%/")
    if tonumber(major_version) == major and tonumber(minor_version) == minor then
        return true
    end
    return false
end

-- Safari
function isSafari(useragent)
    if not isChromiumBased(useragent) and string.match(useragent, "Version%/.* Safari%/") then
        return true
    end
    return false
end

-- встроенный браузер MacOS
function isMacEmbeddedBrowser(useragent)
    if string.match(useragent, "^Mozilla%/[%.%d]+ %(Macintosh;.*Mac OS X [_%d]+%) AppleWebKit%/[%.%d]+ %(KHTML, like Gecko%)$") then
        return true
    end
    return false
end

-- ChromiumBased
function isChromiumBased(useragent)
    if string.match(useragent, "Chrom[e|ium]") then
        return true
    end
    return false
end

-- Chrome версии не меньше, чем <major>
function isChromiumVersionAtLeast(major, useragent)
    local major_version = string.match(useragent, "Chrom[^ %/]+%/(%d+)[%.%d]* ")
    if tonumber(major_version) >= major then
        return true
    end
    return false
end

-- UC Browser
function isUcBrowser(useragent)
    if string.match(useragent, "UCBrowser%/") then
        return true
    end
    return false
end

-- UC Browser версии не меньше, чем <major>.<minor>.<build>
function isUcBrowserVersionAtLeast(major, minor, build, useragent)
    local major_version, minor_version, build_version =
    string.match(useragent, "UCBrowser%/(%d+)%.(%d+)%.(%d+)[%.%d]* ")
    major_version = tonumber(major_version)
    if major_version and major_version ~= major then
        return major_version > major
    end
    minor_version = tonumber(minor_version)
    if minor_version and minor_version ~= minor then
        return minor_version > minor
    end
    build_version = tonumber(build_version)
    if build_version and build_version ~= build then
        return build_version >= build
    end
    return true
end

ngx.var.xsollauid = ngx.var["cookie_xsollauid"]
local contentType = ngx.var.content_type

if ngx.var.xsollauid == nil then
    local xsollauid
    -- если был редирект, то куку снова не генерируем
    if string.match(ngx.var.request_uri, '/hit_check.*') then
        -- значение для столбца ThirdPartyCookieBlocked в hits
        ngx.var.isThirdPartyCookieBlocked = 1
        xsollauid = string.match(ngx.var.request_uri, '/hit_check%?_xm=(%d*)')
        if xsollauid then
            ngx.var.xsollauid = xsollauid
        end
        return true
    end
    -- достаем значение куки xsollauid из url
    xsollauid = string.match(ngx.var.request_uri, '/%w+%?_xm=(%d+)')
    local setCookie
    -- если значение куки xsollauid не задано, то сгенерируем
    if xsollauid == nil then
        local res = ngx.location.capture("/health", {});
        ngx.var.xsollauid = res.header['Xsollauid']
        setCookie = 'xsollauid=' ..  ngx.var.xsollauid .. '; path=/; expires='.. res.header['Expire'] ..'; Domain=.xsolla.com'
    else
        ngx.var.xsollauid = xsollauid
        setCookie = 'xsollauid=' ..  ngx.var.xsollauid .. '; path=/; max-age=315360000; Domain=.xsolla.com'
    end
    local useragent = ngx.req.get_headers()["User_Agent"]
    -- если по юзерагнету определили, что бразуер\клиент не относится к списку несовместимым, то отправим SameSite
    if shouldSendSameSiteNone(useragent) then
        setCookie = setCookie .. '; Secure; SameSite=None'
    end
    ngx.header['Set-Cookie'] = setCookie
    -- отдадим ответ с кодом 307 - редирект на /hit_check
    -- таким образом поймем, установилась ли кука Xsollauid
    if string.match(ngx.var.request_uri, '/hit.*') then
        ngx.var.loggable = 0
        local redirectUrl = '/hit_check?_xm=' .. ngx.var.xsollauid
        ngx.redirect(redirectUrl, ngx.HTTP_TEMPORARY_REDIRECT)
    end
elseif (ngx.var.request_uri == '/hit' or string.match(ngx.var.request_uri, '/hit%?_xm=%d*')) and contentType == 'application/x-www-form-urlencoded' then
    -- если third-paty cookie установлена, то установим(сама установка в js) и first-paty таким же значением
    -- на случай, если в будущем third-paty cookie будут заблокированы
    ngx.print('{"xsollauid":"' .. ngx.var.xsollauid ..'"}')
end