local ss = analiz.libs.serv
local tick = CreateTimeServ()

local mem_ = ss.CreateMemItem(10 * 1024)

local function convert_(message_prop)
    local r = {arr = {}}
    for k, v in pairs(message_prop) do
        r.arr[#r.arr + 1] = {name = k, val = v}
    end
    return r
end

-- -----------------------------------------------------
function CreateBaseTestSystem()
    local r = {}

    function r:sendTest(ctx, xml_body, message_prop, options)
        if options == nil then
            options = {}
            ss.l("send.options is nil")
        end
        ss.l("send.test.options:" .. ss.toJson_sort(options))

        local corrid = ctx.engine_:serv():CreateCorrID()
        local send_option = ss.deepcopy(options)
        --   send_option.prior = options.prior

        --[[16022021
   local sender = ctx.ora.serv --default
   if options.custom_sender~=nil then 
     ss.l("use custom queue:"..options.custom_sender)
     sender = ctx.ora[options.custom_sender]
     if sender==nil then 
       ss.l("failed: not found custom sender:"..options.custom_sender)
     end
   end
--]]

        ss.l("basetestsystem.corrid:" .. corrid)

        ctx.writer_:write({
            prop = convert_(message_prop),
            corrid = corrid,
            body = xml_body
        }, send_option)
        --   sender:send_ver2(convert_(message_prop),corrid,xml_body,send_option)
        if not (options.lazzy_commit) then ctx.writer_:commit() end
        return corrid
    end

    function r:commit(ctx) ctx.engine_:commit() end

    function r:recvTest(ctx, corrid, option)

        if option == nil then
            option = {}
            ss.l("recv.options is nil")
        end
        ss.l("recive.test.options:" .. ss.toJson_sort(options))
        local timeout = ss.def(option.timeout, 60 * 60 * 1) -- default: 1h

        local corrid_ini = corrid
        local start = tick.now()
        local msg
        local wcount = 1
        local emessage=nil
        while true do
            msg,emessage = ctx.reader_:read({timeout = 10, corrid = corrid})


            if ss.def(emessage,"")~="" then 

                local res = {
                    message = {
                        cache = {
                            corrid = corrid_ini,
                            message = "testsystem.reader.failed:"..emessage,
                        }
                    }
                }
                return res
            end
           if not (msg:isnil()) then break end

            if analiz:IsStop() then
                ss.l("baseTestSystem.recvTest.userbreak")
                local res = {
                    message = {
                        cache = {corrid = corrid_ini, message = "userbreak"}
                    }
                }
                return res
            end

            local cur = tick.now()
            local sec = tick.to_sec(cur - start)

            --      if sec>(120*wcount) then
            if sec > (20 * wcount) then
                ss.l("wait:" .. sec .. " sec")
                wcount = wcount + 1
            end

            if sec > timeout then
                ss.l("warning:timeout:" .. sec .. " sec")
                ss.l("corrid:" .. corrid_ini)

                local res = {
                    message = {
                        cache = {
                            corrid = corrid_ini,
                            message = "timeout",
                            time = sec,
                            ["timeout"] = timeout
                        }
                    }
                }
                return res
            end
        end
        ss.l("recive_corrid:" .. msg:getCorrelation())
        local res = {}
        res.body = msg:body()
        res.message = msg:property()

        ctx.reader_:commit()
        ss.l("point2")

        return res

    end

    function r:test(ctx, t, option)

        ss.l("start test:" .. t.test_name)
        if t.message_prop == nil then
            ss.l("failed:t.message_prop is NULL ")
            ss.a("1")
        end

        local corrid = self:sendTest(ctx, t.body, t.message_prop, option)
        local res = self:recvTest(ctx, corrid, option)
        return res
    end


    function r:checkNotProp(ret, names)
        local isok = true
        local emessage = ""
        if ret == nil then
            ss.l("failed:r:checkProp:ret is null")
            emessage = emessage .. "ret is null;"
            isok = false
            ret = {}
        end

        if ret ~= nil and type(ret) ~= "table" then
            ss.l("warning:ret is not table:" .. ret)
            return true, "" 
        end
        if ret.message == nil then
            ss.l("failed:r:checkProp:ret.message is null")
            ss.tprint(ret)
            emessage = emessage .. "ret.message is null"
            isok = false
            ret.message = {}
        end
        for i = 1, #names do
            --    ss.l("check:"..names[i])
            local vv = ret.message.cache[names[i]]

            if vv ~= nil then

                isok = false
                emessage = emessage .. ";failed present field:" .. names[i]
            end
        end
        if not (isok) then
            emessage = emessage .. ss.toJson(ret.message.cache)
        end
        return isok, emessage

    end
    function r:checkProp(ret, names)
        local isok = true
        local emessage = ""
        if ret == nil then
            ss.l("failed:r:checkProp:ret is null")
            emessage = emessage .. "ret is null;"
            isok = false
            ret = {}
        end

        if ret ~= nil and type(ret) ~= "table" then
            ss.l("warning:ret is not table:" .. ret)
            return true, "" 
        end
        if ret.message == nil then
            ss.l("failed:r:checkProp:ret.message is null")
            ss.tprint(ret)
            emessage = emessage .. "ret.message is null"
            isok = false
            ret.message = {}
        end
        for i = 1, #names do
            --    ss.l("check:"..names[i])
            local vv = ret.message.cache[names[i]]

            if vv == nil then
                isok = false
                emessage = emessage .. ";not found prop:" .. names[i]
            end
        end
        if not (isok) then
            emessage = emessage .. ss.toJson(ret.message.cache)
        end
        return isok, emessage
    end

    function r:load_nc_result(bid)
        if bid == nil then return {} end
        ss.e("CREATE_OR_CLEAR_STRING_MAP nc_res")
        ss.s("tmp",
             "select * from namecheck where BUSINESSCASEID='" .. bid .. "'")
        ss.e("ADD_MAP_FROM_SQL_SILEN nc_res AmlWeb $(tmp)")
        return ss.map2obj("nc_res")
    end

    function r:validate(ctx, t, ret)
        ss.l("validate test:" .. t.test_name)
        --  ss.tprint(ret)
        local function add(a, b)
            if a ~= "" then a = a .. "," end
            return a .. b
        end
        local emessage = ""
        -- ss.l("p11.0")
        local count = 0
        local full_ret = ""
        -- ss.l("p11.01")
        if type(ret) == "table" then
            ss.l("p11.01.01")
            full_ret = ss.toJson(ret)
            ss.l("p11.01.02")
        else
            full_ret = ret
        end
        -- ss.l("p11.02")
        --  ss.l("t.2:"..type(t.validate_prop))

        if type(t.validate_prop) == "table" then
            for k, v in pairs(t.validate_prop) do
                local vv = ret.message.cache[k]
                ss.l("ff:" .. k)
                if vv ~= v then
                    emessage = add(emessage, "diff:" .. k .. "real:" ..
                                       ss.def(vv, "<nil>") .. " test:" .. v)
                end
                count = count + 1
            end
        end
        -- ss.l("p11.2")  ss.l("t.3")
        if emessage ~= "" then
            --  ss.l("t.3.1")
            emessage = emessage .. "  ret:" .. ss.toJson_sort(ret.message.cache)
            ss.l("____________________________________________________________")
            return {isok = false, message = emessage, valid_cnt = count}
        end
        --  ss.l("t.4")
        local ex_msg = ""
        if ret.message ~= nil then
            local m = ret.message
            if m.cache ~= nil then
                --    ss.l("t.4.2")
                ex_msg = ss.def(m.cache.CF_HIT_FLAG, "hits is null") ..
                             "\ttodo:score,bid\t"
                ex_msg = ex_msg .. ss.toJson_sort(m.cache)
                --  ss.l("t.3")
            end
        end
        -- ss.l("t.5")
        if ex_msg == "" then
            --      ss.l("t.5") 
            ss.tprint(ret)
            ex_msg = full_ret
        end
        return {isok = true, message = ex_msg, valid_cnt = count}
    end

    local function to_upper_key(a)
        local o = {}
        for k, v in pairs(a) do o[k:upper()] = v end
        return o
    end

    function r:validate_namechecking(ctx, t, ret, options)
        if ret.message == nil then
            ss.l("warning: skip validate_namechecking:ret.message==nil ")
            return true, ""
        end

        local cache = ret.message.cache
        local bid = cache[options.BID]
        local response = cache.CF_HIT_FLAG

        function test_(a, b)
            function fix_(a, t, n)
                if a:find(t) == nil then return a end
                return ss.ReplaceValue(a, t, n)
            end
            if a == nil  then return true end
            if a == b then return true end
            if a == nil or b == nil then return false end
            a = a .. ""
            b = b .. ""
            if (a == b) then return true end
            -- fix enter
            local a1, b1
            a1 = fix_(a, "\n", "")
            a1 = fix_(a1, "\r", "")
            b1 = fix_(b, "\n", "")
            if (a1 == b1) then return true end
            --      ss.l("a1:'"..a1.."'")
            --      ss.l("b1:'"..b1.."'")
            --      ss.a(1)

            -- todo fix

            -- default compare
            return a == b
        end

        function isempty(a)
            local c = 0
            for i, _ in pairs(a) do
                c = c + 1
                break
            end
            return c == 0
        end

        function get_keys(a)
            local keys = {}
            for k, _ in pairs(a) do keys[#keys + 1] = k end
            table.sort(keys)
            return keys
        end

        function check_nc_(keys_arg, send_prop_arg, nc_res, emessage)
            ss.l("check_.log:")
            ss.tprint(keys_arg)
            for i = 1, #keys_arg do
                local k = keys_arg[i]
                local nc_field = k
                if options.rename ~= nil then
                    nc_field = ss.def(options.rename[k], nc_field)
                end

                if nc_field ~= "" then 
                    local val = send_prop_arg[k]
                    local r = nc_res[nc_field]
                    if not (test_(r, val)) then
                        emessage = emessage .. "field:" .. k .. ".nc.val:'" ..
                                       ss.def(r, "<nil>") .. "'  test.val:'" ..
                                       val .. "' ; "
                    end
                end
            end
            return emessage
        end

        local nc_res = to_upper_key(self:load_nc_result(bid))
        --    nc_res.F_PARTNER_CODE=nil
        local send_prop = t.message_prop

        local keys = get_keys(send_prop)

        local emessage = ""
        --    ss.l("namecheck.check:"..#keys)
        --    ss.tprint(t.message_prop)
        if isempty(nc_res) then
            if response == "1" then
                emessage = "record bid=" .. bid .. " not found in NAMECHECK"
            end
        else

            ss.l("keys:")
            ss.tprint(keys)
            emessage = check_nc_(keys, send_prop, nc_res, "")

            if options.validate_nc ~= nil then
                local keys2 = get_keys(options.validate_nc)
                emessage = check_nc_(keys2, options.validate_nc, nc_res,
                                     emessage)
            end

            if emessage ~= "" then
                emessage =
                    "namecheck.prop.error.BID=" .. bid .. ":" .. emessage ..
                        ss.toJson_sort(cache)
            end
        end
        return emessage == "", emessage
    end

    return r
end

testSystem.templates.baseTestSystem = CreateBaseTestSystem()
