local _, addonTable = ...
local core = addonTable

core.MeetingStoneApplicantTestData = core.MeetingStoneApplicantTestData or {}
local TestData = core.MeetingStoneApplicantTestData

_G.MK_MEETINGSTONE_APPLICANT_TEST_ROWS_ENABLED = _G.MK_MEETINGSTONE_APPLICANT_TEST_ROWS_ENABLED == true
_G.MK_MEETINGSTONE_APPLICANT_SCROLL_TEST_EXTRA_ROWS = tonumber(_G.MK_MEETINGSTONE_APPLICANT_SCROLL_TEST_EXTRA_ROWS) or 24

local MEETINGSTONE_APPLICANT_ROLE_KEY_BY_LFG_ROLE = {
    TANK = "TANK",
    HEALER = "HEAL",
    HEAL = "HEAL",
    DAMAGER = "DPS",
    DPS = "DPS",
}

local MEETINGSTONE_APPLICANT_TEST_ACCOUNT_TYPES = {
    {
        name = "测试老兵",
        accountType = "veteran",
        relationship = false,
    },
    {
        name = "测试逃兵",
        accountType = "veteran",
        relationship = false,
        isLeaver = true,
        role = "DAMAGER",
        roleKey = "DPS",
        classFile = "DEMONHUNTER",
        localizedClass = "恶魔猎手",
        specID = 1480,
        comment = "逃兵标识测试：类型列红色显示。",
    },
    {
        name = "测试新兵",
        accountType = "newbie",
    },
    {
        name = "测试新兵无战网",
        accountType = "newbie",
        relationship = false,
    },
    {
        name = "测试火车头",
        accountType = "leader",
        leaderLevel = 0,
    },
    {
        name = "测试星团长",
        accountType = "star",
        starLevel = 0,
        relationship = false,
    },
    {
        name = "测试新兵火车头",
        accountType = "newbie_leader",
        leaderLevel = 3,
        relationship = false,
        comment = "账号类型权重测试：新兵优先于火车头。",
    },
    {
        name = "测试火车头星团长",
        accountType = "leader_star",
        leaderLevel = 2,
        starLevel = 5,
        relationship = false,
        comment = "账号类型权重测试：火车头优先于星团长。",
    },
    {
        name = "测试三职责",
        accountType = "veteran",
        relationship = false,
        role = "TANK",
        roleKey = "TANK",
        roleKeys = { "TANK", "HEAL", "DPS" },
        classFile = "DRUID",
        localizedClass = "德鲁伊",
        specID = 104,
        comment = "三职责申请：坦克、治疗、输出。",
    },
}
local MEETINGSTONE_APPLICANT_TEST_GROUP_APPLICANT_ID = -9001
local MEETINGSTONE_APPLICANT_TEST_GROUP_KEY = "mk-test-party-3"
local MEETINGSTONE_APPLICANT_TEST_GROUP_MEMBERS = {
    {
        name = "测试三人队长",
        accountType = "veteran",
        role = "TANK",
        roleKey = "TANK",
        classFile = "WARRIOR",
        localizedClass = "战士",
        specID = 73,
        relationship = false,
        comment = "三人组队申请：队长。",
    },
    {
        name = "测试三人治疗",
        accountType = "newbie",
        role = "HEALER",
        roleKey = "HEAL",
        classFile = "PRIEST",
        localizedClass = "牧师",
        specID = 257,
        relationship = false,
        comment = "三人组队申请：治疗。",
    },
    {
        name = "测试三人输出",
        accountType = "leader",
        leaderLevel = 4,
        role = "DAMAGER",
        roleKey = "DPS",
        classFile = "MAGE",
        localizedClass = "法师",
        specID = 63,
        relationship = false,
        comment = "三人组队申请：输出。",
    },
}
local MEETINGSTONE_APPLICANT_TEST_SPECS = {
    { specID = 250, localizedSpecName = "鲜血", classFile = "DEATHKNIGHT", localizedClass = "死亡骑士", role = "TANK", roleKey = "TANK" },
    { specID = 251, localizedSpecName = "冰霜", classFile = "DEATHKNIGHT", localizedClass = "死亡骑士", role = "DAMAGER", roleKey = "DPS" },
    { specID = 252, localizedSpecName = "邪恶", classFile = "DEATHKNIGHT", localizedClass = "死亡骑士", role = "DAMAGER", roleKey = "DPS" },
    { specID = 577, localizedSpecName = "浩劫", classFile = "DEMONHUNTER", localizedClass = "恶魔猎手", role = "DAMAGER", roleKey = "DPS" },
    { specID = 581, localizedSpecName = "复仇", classFile = "DEMONHUNTER", localizedClass = "恶魔猎手", role = "TANK", roleKey = "TANK" },
    { specID = 1480, localizedSpecName = "噬灭", classFile = "DEMONHUNTER", localizedClass = "恶魔猎手", role = "DAMAGER", roleKey = "DPS" },
    { specID = 102, localizedSpecName = "平衡", classFile = "DRUID", localizedClass = "德鲁伊", role = "DAMAGER", roleKey = "DPS" },
    { specID = 103, localizedSpecName = "野性", classFile = "DRUID", localizedClass = "德鲁伊", role = "DAMAGER", roleKey = "DPS" },
    { specID = 104, localizedSpecName = "守护", classFile = "DRUID", localizedClass = "德鲁伊", role = "TANK", roleKey = "TANK" },
    { specID = 105, localizedSpecName = "恢复", classFile = "DRUID", localizedClass = "德鲁伊", role = "HEALER", roleKey = "HEAL" },
    { specID = 1467, localizedSpecName = "湮灭", classFile = "EVOKER", localizedClass = "唤魔师", role = "DAMAGER", roleKey = "DPS" },
    { specID = 1468, localizedSpecName = "恩护", classFile = "EVOKER", localizedClass = "唤魔师", role = "HEALER", roleKey = "HEAL" },
    { specID = 1473, localizedSpecName = "增辉", classFile = "EVOKER", localizedClass = "唤魔师", role = "DAMAGER", roleKey = "DPS" },
    { specID = 253, localizedSpecName = "野兽控制", classFile = "HUNTER", localizedClass = "猎人", role = "DAMAGER", roleKey = "DPS" },
    { specID = 254, localizedSpecName = "射击", classFile = "HUNTER", localizedClass = "猎人", role = "DAMAGER", roleKey = "DPS" },
    { specID = 255, localizedSpecName = "生存", classFile = "HUNTER", localizedClass = "猎人", role = "DAMAGER", roleKey = "DPS" },
    { specID = 62, localizedSpecName = "奥术", classFile = "MAGE", localizedClass = "法师", role = "DAMAGER", roleKey = "DPS" },
    { specID = 63, localizedSpecName = "火焰", classFile = "MAGE", localizedClass = "法师", role = "DAMAGER", roleKey = "DPS" },
    { specID = 64, localizedSpecName = "冰霜", classFile = "MAGE", localizedClass = "法师", role = "DAMAGER", roleKey = "DPS" },
    { specID = 268, localizedSpecName = "酒仙", classFile = "MONK", localizedClass = "武僧", role = "TANK", roleKey = "TANK" },
    { specID = 269, localizedSpecName = "踏风", classFile = "MONK", localizedClass = "武僧", role = "DAMAGER", roleKey = "DPS" },
    { specID = 270, localizedSpecName = "织雾", classFile = "MONK", localizedClass = "武僧", role = "HEALER", roleKey = "HEAL" },
    { specID = 65, localizedSpecName = "神圣", classFile = "PALADIN", localizedClass = "圣骑士", role = "HEALER", roleKey = "HEAL" },
    { specID = 66, localizedSpecName = "防护", classFile = "PALADIN", localizedClass = "圣骑士", role = "TANK", roleKey = "TANK" },
    { specID = 70, localizedSpecName = "惩戒", classFile = "PALADIN", localizedClass = "圣骑士", role = "DAMAGER", roleKey = "DPS" },
    { specID = 256, localizedSpecName = "戒律", classFile = "PRIEST", localizedClass = "牧师", role = "HEALER", roleKey = "HEAL" },
    { specID = 257, localizedSpecName = "神圣", classFile = "PRIEST", localizedClass = "牧师", role = "HEALER", roleKey = "HEAL" },
    { specID = 258, localizedSpecName = "暗影", classFile = "PRIEST", localizedClass = "牧师", role = "DAMAGER", roleKey = "DPS" },
    { specID = 259, localizedSpecName = "奇袭", classFile = "ROGUE", localizedClass = "潜行者", role = "DAMAGER", roleKey = "DPS" },
    { specID = 260, localizedSpecName = "狂徒", classFile = "ROGUE", localizedClass = "潜行者", role = "DAMAGER", roleKey = "DPS" },
    { specID = 261, localizedSpecName = "敏锐", classFile = "ROGUE", localizedClass = "潜行者", role = "DAMAGER", roleKey = "DPS" },
    { specID = 262, localizedSpecName = "元素", classFile = "SHAMAN", localizedClass = "萨满祭司", role = "DAMAGER", roleKey = "DPS" },
    { specID = 263, localizedSpecName = "增强", classFile = "SHAMAN", localizedClass = "萨满祭司", role = "DAMAGER", roleKey = "DPS" },
    { specID = 264, localizedSpecName = "恢复", classFile = "SHAMAN", localizedClass = "萨满祭司", role = "HEALER", roleKey = "HEAL" },
    { specID = 265, localizedSpecName = "痛苦", classFile = "WARLOCK", localizedClass = "术士", role = "DAMAGER", roleKey = "DPS" },
    { specID = 266, localizedSpecName = "恶魔学识", classFile = "WARLOCK", localizedClass = "术士", role = "DAMAGER", roleKey = "DPS" },
    { specID = 267, localizedSpecName = "毁灭", classFile = "WARLOCK", localizedClass = "术士", role = "DAMAGER", roleKey = "DPS" },
    { specID = 71, localizedSpecName = "武器", classFile = "WARRIOR", localizedClass = "战士", role = "DAMAGER", roleKey = "DPS" },
    { specID = 72, localizedSpecName = "狂怒", classFile = "WARRIOR", localizedClass = "战士", role = "DAMAGER", roleKey = "DPS" },
    { specID = 73, localizedSpecName = "防护", classFile = "WARRIOR", localizedClass = "战士", role = "TANK", roleKey = "TANK" },
}
local MEETINGSTONE_APPLICANT_TEST_ACCOUNT_TYPE_KEYS = {
    "veteran",
    "newbie",
    "leader",
    "star",
}
local MEETINGSTONE_APPLICANT_TEST_COMMENTS = {
    "可语音，熟路线。",
    "自备合剂和爆发药水。",
    "有门有糖，稳定不毛。",
    "来测列表 UI。",
    "熟练打断，能开麦。",
}
local MEETINGSTONE_APPLICANT_TEST_SINGLE_APPLICANT_ID_BASE = -8000

local function BuildMeetingStoneApplicantTestRoleFlags(primaryRoleKey, roleKeys)
    local roles = {
        TANK = false,
        HEAL = false,
        DPS = false,
    }

    local function addRole(roleKey)
        if type(roleKey) ~= "string" then
            return
        end

        local normalizedRoleKey = MEETINGSTONE_APPLICANT_ROLE_KEY_BY_LFG_ROLE[roleKey]
        if normalizedRoleKey and roles[normalizedRoleKey] ~= nil then
            roles[normalizedRoleKey] = true
        end
    end

    if type(roleKeys) == "table" then
        for _, roleKey in ipairs(roleKeys) do
            addRole(roleKey)
        end
    end

    addRole(primaryRoleKey)

    if not (roles.TANK or roles.HEAL or roles.DPS) then
        roles.DPS = true
    end

    return roles
end

local function GetMeetingStoneApplicantRandomValue(values)
    if type(values) ~= "table" or #values == 0 then
        return nil
    end

    if random then
        return values[random(1, #values)]
    end

    return values[1]
end

local function GetMeetingStoneApplicantRandomNumber(minValue, maxValue)
    if random then
        return random(minValue, maxValue)
    end

    return minValue
end

local function GetMeetingStoneApplicantTestSpecByID(specID)
    specID = tonumber(specID)
    if not specID then
        return nil
    end

    for _, specInfo in ipairs(MEETINGSTONE_APPLICANT_TEST_SPECS) do
        if specInfo.specID == specID then
            return specInfo
        end
    end

    return nil
end

local function GetMeetingStoneApplicantRandomSpec(roleKey, classFile)
    local normalizedRoleKey = MEETINGSTONE_APPLICANT_ROLE_KEY_BY_LFG_ROLE[roleKey or ""]
    local normalizedClassFile = type(classFile) == "string" and classFile:upper() or nil
    local candidates = {}

    local function collect(matchRole, matchClass)
        for _, specInfo in ipairs(MEETINGSTONE_APPLICANT_TEST_SPECS) do
            local roleMatches = not matchRole or specInfo.roleKey == normalizedRoleKey
            local classMatches = not matchClass or specInfo.classFile == normalizedClassFile
            if roleMatches and classMatches then
                candidates[#candidates + 1] = specInfo
            end
        end
    end

    if normalizedRoleKey and normalizedClassFile then
        collect(true, true)
    end
    if #candidates == 0 and normalizedClassFile then
        collect(false, true)
    end
    if #candidates == 0 and normalizedRoleKey then
        collect(true, false)
    end
    if #candidates == 0 then
        collect(false, false)
    end

    return GetMeetingStoneApplicantRandomValue(candidates) or MEETINGSTONE_APPLICANT_TEST_SPECS[1]
end

local function ResolveMeetingStoneApplicantTestSpec(testInfo, fallbackRoleKey)
    local specInfo = GetMeetingStoneApplicantTestSpecByID(testInfo and testInfo.specID)
    if specInfo then
        return specInfo
    end

    return GetMeetingStoneApplicantRandomSpec(
        testInfo and (testInfo.roleKey or testInfo.role) or fallbackRoleKey,
        testInfo and testInfo.classFile
    )
end

local function SeedMeetingStoneApplicantTestAccountType(applicant)
    if not (applicant and applicant.mkMeetingStoneTestRow and core.AccountType and core.AccountType.SetTestIdentity) then
        return
    end

    local now = time and time() or 0
    local accountType = applicant.mkMeetingStoneTestAccountType
    local identity
    if accountType == "newbie" then
        identity = {
            isNewbie = true,
            newbieExpireTime = now + (24 * 60 * 60),
        }
    elseif accountType == "newbie_leader" then
        identity = {
            isNewbie = true,
            newbieExpireTime = now + (24 * 60 * 60),
            level = applicant.mkMeetingStoneTestLeaderLevel or 3,
            starLevel = applicant.mkMeetingStoneTestStarLevel,
        }
    elseif accountType == "leader" then
        identity = {
            level = applicant.mkMeetingStoneTestLeaderLevel or 0,
        }
    elseif accountType == "leader_star" then
        identity = {
            level = applicant.mkMeetingStoneTestLeaderLevel or 2,
            starLevel = applicant.mkMeetingStoneTestStarLevel or 5,
        }
    elseif accountType == "star" then
        identity = {
            starLevel = applicant.mkMeetingStoneTestStarLevel or 0,
        }
    else
        identity = {}
    end

    identity.updatedAt = now
    core.AccountType.SetTestIdentity(applicant.name, nil, identity)
end

local function ApplyMeetingStoneApplicantTestBlacklistState(owner, applicant)
    if not (owner and owner.IsPlayerBlacklisted and applicant and applicant.mkMeetingStoneTestRow) then
        return
    end
    if type(applicant.name) ~= "string" or applicant.name == "" then
        return
    end

    local isBlacklisted, record, key = owner:IsPlayerBlacklisted(applicant.name)
    applicant.isBlacklisted = isBlacklisted == true
    applicant.blacklistRecord = record
    applicant.blacklistKey = key
end

local function PrepareMeetingStoneApplicantTestRow(owner, applicant)
    SeedMeetingStoneApplicantTestAccountType(applicant)
    ApplyMeetingStoneApplicantTestBlacklistState(owner, applicant)
end

local function CreateMeetingStoneApplicantTestRows(owner, activityID, isMythicPlusActivity)
    if _G.MK_MEETINGSTONE_APPLICANT_TEST_ROWS_ENABLED ~= true then
        return nil
    end

    if owner and owner.mkMeetingStoneTestApplicants then
        for _, applicant in ipairs(owner.mkMeetingStoneTestApplicants) do
            PrepareMeetingStoneApplicantTestRow(owner, applicant)
        end
        return owner.mkMeetingStoneTestApplicants
    end

    local realm = GetRealmName and GetRealmName() or "测试服"
    if type(realm) == "string" then
        realm = realm:gsub("%s+", "")
    end
    if type(realm) ~= "string" or realm == "" then
        realm = "测试服"
    end

    local applicants = {}
    for index, testInfo in ipairs(MEETINGSTONE_APPLICANT_TEST_ACCOUNT_TYPES) do
        local specInfo = ResolveMeetingStoneApplicantTestSpec(testInfo)
        local score = GetMeetingStoneApplicantRandomNumber(2600, 3600)
        local bestMapScore = math.max(1, score - GetMeetingStoneApplicantRandomNumber(120, 420))
        local applicant = {
            applicantID = MEETINGSTONE_APPLICANT_TEST_SINGLE_APPLICANT_ID_BASE - index,
            memberIndex = 1,
            numMembers = 1,
            name = string.format("%s-%s", testInfo.name, realm),
            shortName = testInfo.name,
            role = testInfo.role or specInfo.role,
            roles = BuildMeetingStoneApplicantTestRoleFlags(testInfo.roleKey or specInfo.roleKey, testInfo.roleKeys),
            level = 90,
            honorLevel = GetMeetingStoneApplicantRandomNumber(10, 120),
            useHonorLevel = false,
            relationship = testInfo.relationship ~= false,
            isLeaver = testInfo.isLeaver == true,
            class = testInfo.localizedClass or specInfo.localizedClass,
            classFile = testInfo.classFile or specInfo.classFile,
            specID = testInfo.specID or specInfo.specID,
            specName = testInfo.localizedSpecName or specInfo.localizedSpecName,
            score = score,
            bestScore = {
                mapScore = bestMapScore,
                bestRunLevel = GetMeetingStoneApplicantRandomNumber(8, 16),
                finishedSuccess = GetMeetingStoneApplicantRandomNumber(1, 2) == 1,
            },
            stats = {},
            activityID = activityID,
            isMythicPlusActivity = isMythicPlusActivity == true,
            itemLevel = GetMeetingStoneApplicantRandomNumber(285, 305),
            comment = testInfo.comment or GetMeetingStoneApplicantRandomValue(MEETINGSTONE_APPLICANT_TEST_COMMENTS),
            applicationStatus = "applied",
            pendingApplicationStatus = nil,
            displayOrderID = index,
            statusRank = 40,
            sourceIndex = index,
            mkMeetingStoneTestRow = true,
            mkMeetingStoneTestAccountType = testInfo.accountType,
            mkMeetingStoneTestLeaderLevel = testInfo.leaderLevel,
            mkMeetingStoneTestStarLevel = testInfo.starLevel,
        }
        applicants[#applicants + 1] = applicant
    end

    local extraRowCount = math.max(0, math.floor(tonumber(_G.MK_MEETINGSTONE_APPLICANT_SCROLL_TEST_EXTRA_ROWS) or 0))
    for extraIndex = 1, extraRowCount do
        local specInfo = GetMeetingStoneApplicantRandomSpec()
        local accountType = GetMeetingStoneApplicantRandomValue(MEETINGSTONE_APPLICANT_TEST_ACCOUNT_TYPE_KEYS) or "veteran"
        local score = GetMeetingStoneApplicantRandomNumber(2600, 3600)
        local bestMapScore = math.max(1, score - GetMeetingStoneApplicantRandomNumber(120, 420))
        local displayIndex = #applicants + 1
        local shortName = string.format("滚动测试%02d", extraIndex)
        local applicant = {
            applicantID = MEETINGSTONE_APPLICANT_TEST_SINGLE_APPLICANT_ID_BASE - 100 - extraIndex,
            memberIndex = 1,
            numMembers = 1,
            name = string.format("%s-%s", shortName, realm),
            shortName = shortName,
            role = specInfo.role,
            roles = BuildMeetingStoneApplicantTestRoleFlags(specInfo.roleKey),
            level = 90,
            honorLevel = GetMeetingStoneApplicantRandomNumber(10, 120),
            useHonorLevel = false,
            relationship = GetMeetingStoneApplicantRandomNumber(1, 3) == 1,
            class = specInfo.localizedClass,
            classFile = specInfo.classFile,
            specID = specInfo.specID,
            specName = specInfo.localizedSpecName,
            score = score,
            bestScore = {
                mapScore = bestMapScore,
                bestRunLevel = GetMeetingStoneApplicantRandomNumber(8, 16),
                finishedSuccess = GetMeetingStoneApplicantRandomNumber(1, 2) == 1,
            },
            stats = {},
            activityID = activityID,
            isMythicPlusActivity = isMythicPlusActivity == true,
            itemLevel = GetMeetingStoneApplicantRandomNumber(285, 305),
            comment = GetMeetingStoneApplicantRandomValue(MEETINGSTONE_APPLICANT_TEST_COMMENTS),
            applicationStatus = "applied",
            pendingApplicationStatus = nil,
            displayOrderID = displayIndex,
            statusRank = 40,
            sourceIndex = displayIndex,
            mkMeetingStoneTestRow = true,
            mkMeetingStoneTestAccountType = accountType,
            mkMeetingStoneTestLeaderLevel = accountType == "leader" and GetMeetingStoneApplicantRandomNumber(1, 5) or nil,
            mkMeetingStoneTestStarLevel = accountType == "star" and GetMeetingStoneApplicantRandomNumber(1, 5) or nil,
        }
        applicants[#applicants + 1] = applicant
    end

    local groupOffset = #applicants
    for memberIndex, testInfo in ipairs(MEETINGSTONE_APPLICANT_TEST_GROUP_MEMBERS) do
        local specInfo = ResolveMeetingStoneApplicantTestSpec(testInfo, testInfo.roleKey)
        local score = GetMeetingStoneApplicantRandomNumber(2600, 3600)
        local bestMapScore = math.max(1, score - GetMeetingStoneApplicantRandomNumber(120, 420))
        local applicant = {
            applicantID = MEETINGSTONE_APPLICANT_TEST_GROUP_APPLICANT_ID,
            memberIndex = memberIndex,
            numMembers = #MEETINGSTONE_APPLICANT_TEST_GROUP_MEMBERS,
            name = string.format("%s-%s", testInfo.name, realm),
            shortName = testInfo.name,
            role = testInfo.role,
            roles = {
                TANK = testInfo.roleKey == "TANK",
                HEAL = testInfo.roleKey == "HEAL",
                DPS = testInfo.roleKey == "DPS",
            },
            level = 90,
            honorLevel = GetMeetingStoneApplicantRandomNumber(10, 120),
            useHonorLevel = false,
            relationship = testInfo.relationship == true,
            class = testInfo.localizedClass or specInfo.localizedClass,
            classFile = testInfo.classFile or specInfo.classFile,
            specID = testInfo.specID or specInfo.specID,
            specName = testInfo.localizedSpecName or specInfo.localizedSpecName,
            score = score,
            bestScore = {
                mapScore = bestMapScore,
                bestRunLevel = GetMeetingStoneApplicantRandomNumber(8, 16),
                finishedSuccess = GetMeetingStoneApplicantRandomNumber(1, 2) == 1,
            },
            stats = {},
            activityID = activityID,
            isMythicPlusActivity = isMythicPlusActivity == true,
            itemLevel = GetMeetingStoneApplicantRandomNumber(285, 305),
            comment = testInfo.comment or GetMeetingStoneApplicantRandomValue(MEETINGSTONE_APPLICANT_TEST_COMMENTS),
            applicationStatus = "applied",
            pendingApplicationStatus = nil,
            displayOrderID = groupOffset + memberIndex,
            statusRank = 40,
            sourceIndex = groupOffset + memberIndex,
            mkMeetingStoneTestRow = true,
            mkMeetingStoneTestGroupKey = MEETINGSTONE_APPLICANT_TEST_GROUP_KEY,
            mkMeetingStoneTestAccountType = testInfo.accountType,
            mkMeetingStoneTestLeaderLevel = testInfo.leaderLevel,
            mkMeetingStoneTestStarLevel = testInfo.starLevel,
        }
        applicants[#applicants + 1] = applicant
    end

    if owner then
        owner.mkMeetingStoneTestApplicant = nil
        owner.mkMeetingStoneTestApplicants = applicants
    end
    for _, applicant in ipairs(applicants) do
        PrepareMeetingStoneApplicantTestRow(owner, applicant)
    end
    return applicants
end

TestData.SeedAccountType = SeedMeetingStoneApplicantTestAccountType
TestData.PrepareRow = PrepareMeetingStoneApplicantTestRow
TestData.CreateRows = CreateMeetingStoneApplicantTestRows
