--## Author: Bettiold ## Version: 1.0 ## SavedVariables: BountyHelperDB, dbBH  汉化:电视卫士
local db = {}
db.instanceOrderList = {
    249, 329, 532, 550, 556, 575, 585, 603, 616, 624, 631, 657, 720, 725,
    754, 859, 967, 1008, 1098, 1136, 1205, 1448, 1530, 1651, 1676, 1712,
    1754, 1762, 1841, 2070, 2097, 2217, 2286, 2441, 2450, 2481, 2549, 2651,
    2657, 2769, 2810
}
db.waypoints = {
    [249] = {point = {70, 0.5217, 0.7595}},
    [329] = {point = {23, 0.4361, 0.1756}},
    [532] = {point = {42, 0.4715, 0.7494}},
    [550] = {point = {109, 0.7329, 0.6386}},
    [556] = {point = {108, 0.4455, 0.6549}},
    [575] = {point = {117, 0.572, 0.4652}},
    [585] = {point = {122, 0.6082, 0.3077}},
    [603] = {point = {120, 0.4179, 0.1754}},
    [616] = {point = {114, 0.2756, 0.2677}},
    [624] = {point = {123, 0.5008, 0.1189}},
    [631] = {point = {118, 0.5391, 0.8729}},
    [657] = {point = {249, 0.7665, 0.8433}},
    [720] = {point = {198, 0.4647, 0.7812}},
    [725] = {point = {207, 0.4743, 0.5254}},
    [754] = {point = {249, 0.3712, 0.8162}},
    [859] = {point = {50, 0.7219, 0.3284}},
    [967] = {point = {75, 0.6103, 0.2105}},
    [1008] = {point = {379, 0.5967, 0.3963}},
    [1098] = {point = {504, 0.6379, 0.3220}},
    [1136] = {point = {390, 0.7421, 0.4202}},
    [1205] = {point = {543, 0.5146, 0.2710}},
    [1448] = {point = {534, 0.4689, 0.5213}},
    [1530] = {point = {680, 0.4349, 0.5707}},
    [1651] = {point = {42, 0.467, 0.701}},
    [1676] = {point = {646, 0.6397, 0.2138}},
    [1712] = {point = {885, 0.5486, 0.6256}},
    [1754] = {point = {895, 0.843, 0.7836}},
    [1762] = {point = {862, 0.3712, 0.3938}},
    [1841] = {point = {863, 0.5125, 0.6472}},
    [2070] = {point = {{895, 0.7444, 0.2853}, {862, 0.5421, 0.2991}}},
    [2097] = {point = {1462, 0.7302, 0.3652}},
    [2217] = {point = {{1527, 0.5519, 0.4398}, {1530, 0.3973, 0.4628}}},
    [2286] = {point = {1533, 0.4017, 0.5516}},
    [2441] = {point = {1550, 0.3154, 0.7609, 2016}},
    [2450] = {point = {1543, 0.6974, 0.322}},
    [2481] = {point = {1970, 0.8026, 0.5302}},
    [2549] = {point = {2200, 0.2753, 0.3100}},
    [2651] = {point = {2214, 0.4285, 0.0882}},
    [2657] = {point = {2255, 0.4360, 0.8976}},
    [2769] = {point = {2346, 0.4132, 0.4862}},
    [2810] = {point = {2371, 0.4179, 0.2146}}
}

db.bossData = {
    [249] = { -- Onyxia's Lair
        { name = "Onyxia", encounterID = 1651, killedAtDiff = { [3] = false, [4] = false } },
    },
    [329] = { -- Stratholme
        { name = "Lord Aurius Rivendare", encounterID = 456, killedAtDiff = { [1] = false } },
        { name = "Hearthsinger Forresten", encounterID = 443, killedAtDiff = { [1] = false } },
    },
    [532] = { -- Karazhan
        { name = "Attumen the Huntsman", encounterID = 1553, killedAtDiff = { [3] = false } },
    },
    [550] = { -- The Eye
        { name = "Kael'thas Sunstrider", encounterID = 1576, killedAtDiff = { [4] = false } },
    },
    [556] = { -- Sethekk Halls
        { name = "Anzu", encounterID = 542, killedAtDiff = { [2] = false } },
    },
    [575] = { -- Utgarde Pinnacle
        { name = "Skadi the Ruthless", encounterID = 643, killedAtDiff = { [2] = false } },
    },
    [585] = { -- Magisters' Terrace
        { name = "Kael'thas Sunstrider", encounterID = 533, killedAtDiff = { [2] = false } },
    },
    [603] = { -- Ulduar
        { name = "Yogg-Saron", encounterID = 1649, killedAtDiff = { [14] = false } },
    },
    [616] = { -- The Eye of Eternity
        { name = "Malygos", encounterID = 1617, killedAtDiff = { [3] = false, [4] = false } },
    },
    [624] = { -- Vault of Archavon
        { name = "Archavon the Stone Watcher", encounterID = 1597, killedAtDiff = { [3] = false, [4] = false } },
        { name = "Emalon the Storm Watcher", encounterID = 1598, killedAtDiff = { [3] = false, [4] = false } },
        { name = "Koralon the Flame Watcher", encounterID = 1599, killedAtDiff = { [3] = false, [4] = false } },
        { name = "Toravon the Ice Watcher", encounterID = 1600, killedAtDiff = { [3] = false, [4] = false } },
    },
    [631] = { -- Icecrown Citadel
        { name = "The Lich King", encounterID = 1636, killedAtDiff = { [6] = false } },
    },
    [657] = { -- The Vortex Pinnacle
        { name = "Altairus", encounterID = 115, killedAtDiff = { [1] = false, [2] = false } },
    },
    [720] = { -- Firelands
        { name = "Alysrazor", encounterID = 194, killedAtDiff = { [14] = false, [15] = false } },
        { name = "Ragnaros", encounterID = 198, killedAtDiff = { [14] = false, [15] = false } },
    },
    [725] = { -- The Stonecore
        { name = "Slabhide", encounterID = 111, killedAtDiff = { [1] = false, [2] = false } },
    },
    [754] = { -- Throne of the Four Winds
        { name = "Al'Akir", encounterID = 155, killedAtDiff = { [3] = false, [4] = false, [5] = false, [6] = false } },
    },
    [859] = { -- Zul'Gurub
        { name = "Bloodlord Mandokir", encounterID = 176, killedAtDiff = { [2] = false } },
        { name = "High Priestess Kilnara", encounterID = 181, killedAtDiff = { [2] = false } },
    },
    [967] = { -- Dragon Soul
        { name = "Ultraxion", encounterID = 331, killedAtDiff = { [3] = false, [4] = false, [5] = false, [6] = false } },
        { name = "Madness of Deathwing", encounterID = 333, killedAtDiff = { [3] = false, [4] = false, [5] = false, [6] = false } },
    },
    [1008] = { -- Mogu'shan Vaults
        { name = "Elegon", encounterID = 726, killedAtDiff = { [3] = false, [4] = false, [5] = false, [6] = false } },
    },
    [1098] = { -- Throne of Thunder
        { name = "Horridon", encounterID = 819, killedAtDiff = { [3] = false, [4] = false, [5] = false, [6] = false } },
        { name = "Ji-Kun", encounterID = 828, killedAtDiff = { [3] = false, [4] = false, [5] = false, [6] = false } },
    },
    [1136] = { -- Siege of Orgrimmar
        { name = "Garrosh Hellscream", encounterID = 869, killedAtDiff = { [16] = false } },
    },
    [1205] = { -- Blackrock Foundry
        { name = "Blackhand", encounterID = 959, killedAtDiff = { [16] = false } },
    },
    [1448] = { -- Hellfire Citadel
        { name = "Archimonde", encounterID = 1438, killedAtDiff = { [16] = false } },
    },
    [1530] = { -- The Nighthold
        { name = "Gul'dan", encounterID = 1737, killedAtDiff = { [14] = false, [15] = false, [16] = false } },
    },
    [1651] = { -- Return to Karazhan
        { name = "Attumen the Huntsman", encounterID = 1835, killedAtDiff = { [23] = false } },
    },
    [1676] = { -- Tomb of Sargeras
        { name = "Mistress Sassz'ine", encounterID = 1861, killedAtDiff = { [14] = false, [15] = false, [16] = false, [17] = false } },
    },
    [1712] = { -- Antorus, the Burning Throne
        { name = "Felhounds of Sargeras", encounterID = 1987, killedAtDiff = { [14] = false, [15] = false, [16] = false, [17] = false } },
        { name = "Argus the Unmaker", encounterID = 2031, killedAtDiff = { [16] = false } },
    },
    [1754] = { -- Freehold
        { name = "Lord Harlan Sweete", encounterID = 2095, killedAtDiff = { [23] = false } },
    },
    [1762] = { -- Kings' Rest
        { name = "King Dazar", encounterID = 2172, killedAtDiff = { [23] = false } },
    },
    [1841] = { -- The Underrot
        { name = "Unbound Abomination", encounterID = 2158, killedAtDiff = { [23] = false } },
    },
    [2070] = { -- Battle of Dazar'alor
        { name = "Mekkatorque", encounterID = 2334, killedAtDiff = { [14] = false, [15] = false, [16] = false } },
        { name = "Lady Jaina Proudmoore", encounterID = 2343, killedAtDiff = { [16] = false, [17] = false } },
    },
    [2097] = { -- Operation: Mechagon
        { name = "HK-8 Aerial Oppression Unit", encounterID = 2355, killedAtDiff = { [23] = false } },
    },
    [2217] = { -- Ny'alotha, the Waking City
        { name = "N'Zoth the Corruptor", encounterID = 2375, killedAtDiff = { [16] = false } },
    },
    [2286] = { -- The Necrotic Wake
        { name = "Nalthor the Rimebinder", encounterID = 2396, killedAtDiff = { [23] = false } },
    },
    [2441] = { -- Tazavesh, the Veiled Market
        { name = "So'leah", encounterID = 2455, killedAtDiff = { [2] = false, [23] = false } },
    },
    [2450] = { -- Sanctum of Domination
        { name = "The Nine", encounterID = 2439, killedAtDiff = { [14] = false, [15] = false, [16] = false, [17] = false } },
        { name = "Sylvanas Windrunner", encounterID = 2441, killedAtDiff = { [16] = false } },
    },
    [2481] = { -- Sepulcher of the First Ones
        { name = "The Jailer", encounterID = 2464, killedAtDiff = { [16] = false } },
    },
    [2549] = { -- Amirdrassil, the Dream's Hope
        { name = "Fyrakk the Blazing", encounterID = 2519, killedAtDiff = { [16] = false } },
        { name = "Larodar, Keeper of the Flame", encounterID = 2553, killedAtDiff = { [14] = false, [15] = false, [16] = false } }
    },
    [2651] = { -- Darkflame Cleft
        { name = "The Darkness", encounterID = 2561, killedAtDiff = { [23] = false } }
    },
    [2657] = { -- Nerub-ar Palace
        { name = "Queen Ansurek", encounterID = 2602, killedAtDiff = { [14] = false, [15] = false, [16] = false, [17] = false } }
    },
    [2769] = { -- Liberation of Undermine
        { name = "Chrome King Gallywix", encounterID = 2646, killedAtDiff = { [14] = false, [15] = false, [16] = false, [17] = false } },
        { name = "Stix Bunkjunker", encounterID = 2642, killedAtDiff = { [14] = false, [15] = false, [16] = false, [17] = false } }
    },
    [2810] = { -- Manaforge Omega
        { name = "Dimensius, the All-Devouring", encounterID = 2691, killedAtDiff = { [14] = false, [15] = false, [16] = false, [17] = false } }
    }
}

-- mountData is indexed by mountID.
-- `dropsBy` contains a list of all sources for the mount.
-- `index` refers to the boss's position in the `bossData[instanceID]` table above.
db.mountData = {
    [13335] = { journalMountID = 69, dropsBy = {
        { instanceID = 329, diff = 1, index = 1, chance = 0.9, repeatable = true },
    }},
    [30480] = { journalMountID = 168, dropsBy = {
        { instanceID = 532, diff = 3, index = 1, chance = 1.1 },
    }},
    [32458] = { journalMountID = 183, dropsBy = {
        { instanceID = 550, diff = 4, index = 1, chance = 1.7 },
    }},
    [32768] = { journalMountID = 185, dropsBy = {
        { instanceID = 556, diff = 2, index = 1, chance = 1.6 },
    }},
    [35513] = { journalMountID = 213, dropsBy = {
        { instanceID = 585, diff = 2, index = 1, chance = 4.0 },
    }},
    [43952] = { journalMountID = 246, dropsBy = {
        { instanceID = 616, diff = 3, index = 1, chance = 3.0 },
        { instanceID = 616, diff = 4, index = 1, chance = 3.0 },
    }},
    [43953] = { journalMountID = 247, dropsBy = {
        { instanceID = 616, diff = 3, index = 1, chance = 4.0 },
        { instanceID = 616, diff = 4, index = 1, chance = 4.0 },
    }},
    [43959] = { journalMountID = 286, dropsBy = {
        { instanceID = 624, diff = 3, index = 1, chance = 1.1 }, { instanceID = 624, diff = 4, index = 1, chance = 1.1 },
        { instanceID = 624, diff = 3, index = 2, chance = 1.0 }, { instanceID = 624, diff = 4, index = 2, chance = 1.0 },
        { instanceID = 624, diff = 3, index = 3, chance = 1.0 }, { instanceID = 624, diff = 4, index = 3, chance = 1.0 },
        { instanceID = 624, diff = 3, index = 4, chance = 0.8 }, { instanceID = 624, diff = 4, index = 4, chance = 0.8 },
    }},
    [44151] = { journalMountID = 264, dropsBy = {
        { instanceID = 575, diff = 2, index = 1, chance = 0.8 },
    }},
    [45693] = { journalMountID = 304, dropsBy = {
        { instanceID = 603, diff = 14, index = 1, chance = 1.0 },
    }},
    [49636] = { journalMountID = 349, dropsBy = {
        { instanceID = 249, diff = 3, index = 1, chance = 1.5 },
        { instanceID = 249, diff = 4, index = 1, chance = 1.5 },
    }},
    [50818] = { journalMountID = 363, dropsBy = {
        { instanceID = 631, diff = 6, index = 1, chance = 0.8 },
    }},
    [63040] = { journalMountID = 395, dropsBy = {
        { instanceID = 657, diff = 1, index = 1, chance = 0.7 },
        { instanceID = 657, diff = 2, index = 1, chance = 0.7 },
    }},
    [63041] = { journalMountID = 396, dropsBy = {
        { instanceID = 754, diff = 3, index = 1, chance = 2.0 }, { instanceID = 754, diff = 4, index = 1, chance = 2.0 },
        { instanceID = 754, diff = 5, index = 1, chance = 2.0 }, { instanceID = 754, diff = 6, index = 1, chance = 2.0 },
    }},
    [63043] = { journalMountID = 397, dropsBy = {
        { instanceID = 725, diff = 1, index = 1, chance = 0.7 },
        { instanceID = 725, diff = 2, index = 1, chance = 0.7 },
    }},
    [68823] = { journalMountID = 410, dropsBy = {
        { instanceID = 859, diff = 2, index = 1, chance = 0.7 },
    }},
    [68824] = { journalMountID = 411, dropsBy = {
        { instanceID = 859, diff = 2, index = 2, chance = 0.9 },
    }},
    [69224] = { journalMountID = 415, dropsBy = {
        { instanceID = 720, diff = 14, index = 2, chance = 1.7 },
        { instanceID = 720, diff = 15, index = 2, chance = 1.7 },
    }},
    [71665] = { journalMountID = 425, dropsBy = {
        { instanceID = 720, diff = 14, index = 1, chance = 2.0 },
        { instanceID = 720, diff = 15, index = 1, chance = 2.0 },
    }},
    [77067] = { journalMountID = 442, dropsBy = {
        { instanceID = 967, diff = 3, index = 2, chance = 3.0 }, { instanceID = 967, diff = 4, index = 2, chance = 3.0 },
        { instanceID = 967, diff = 5, index = 2, chance = 3.0 }, { instanceID = 967, diff = 6, index = 2, chance = 3.0 },
    }},
    [77069] = { journalMountID = 444, dropsBy = {
        { instanceID = 967, diff = 5, index = 2, chance = 1.8 },
        { instanceID = 967, diff = 6, index = 2, chance = 1.8 },
    }},
    [78919] = { journalMountID = 445, dropsBy = {
        { instanceID = 967, diff = 3, index = 1, chance = 1.2 }, { instanceID = 967, diff = 4, index = 1, chance = 1.2 },
        { instanceID = 967, diff = 5, index = 1, chance = 1.2 }, { instanceID = 967, diff = 6, index = 1, chance = 1.2 },
    }},
    [87777] = { journalMountID = 478, dropsBy = {
        { instanceID = 1008, diff = 3, index = 1, chance = 4.0 }, { instanceID = 1008, diff = 4, index = 1, chance = 4.0 },
        { instanceID = 1008, diff = 5, index = 1, chance = 4.0 }, { instanceID = 1008, diff = 6, index = 1, chance = 4.0 },
    }},
    [93666] = { journalMountID = 531, dropsBy = {
        { instanceID = 1098, diff = 3, index = 1, chance = 2.0 }, { instanceID = 1098, diff = 4, index = 1, chance = 2.0 },
        { instanceID = 1098, diff = 5, index = 1, chance = 2.0 }, { instanceID = 1098, diff = 6, index = 1, chance = 2.0 },
    }},
    [95059] = { journalMountID = 543, dropsBy = {
        { instanceID = 1098, diff = 3, index = 2, chance = 2.0 }, { instanceID = 1098, diff = 4, index = 2, chance = 2.0 },
        { instanceID = 1098, diff = 5, index = 2, chance = 2.0 }, { instanceID = 1098, diff = 6, index = 2, chance = 2.0 },
    }},
    [104253] = { journalMountID = 559, dropsBy = {
        { instanceID = 1136, diff = 16, index = 1, chance = 0.9 },
    }},
    [116660] = { journalMountID = 613, dropsBy = {
        { instanceID = 1205, diff = 16, index = 1, chance = 2.0 },
    }},
    [123890] = { journalMountID = 751, dropsBy = {
        { instanceID = 1448, diff = 16, index = 1, chance = 4.0 },
    }},
    [137574] = { journalMountID = 791, dropsBy = {
        { instanceID = 1530, diff = 14, index = 1, chance = 0.5 },
        { instanceID = 1530, diff = 15, index = 1, chance = 0.5 },
        { instanceID = 1530, diff = 16, index = 1, chance = 0.5 },
    }},
    [137575] = { journalMountID = 633, dropsBy = {
        { instanceID = 1530, diff = 16, index = 1, chance = 1.0 },
    }},
    [142236] = { journalMountID = 875, dropsBy = {
        { instanceID = 1651, diff = 23, index = 1, chance = 0.9 },
    }},
    [143643] = { journalMountID = 899, dropsBy = {
        { instanceID = 1676, diff = 17, index = 1, chance = 0.2, lfr = {619, 0.4647, 0.6488, 627}, wing = 1494}, { instanceID = 1676, diff = 14, index = 1, chance = 0.2 },
        { instanceID = 1676, diff = 15, index = 1, chance = 0.2 }, { instanceID = 1676, diff = 16, index = 1, chance = 0.2 }
    }},
    [152789] = { journalMountID = 954, dropsBy = {
        { instanceID = 1712, diff = 16, index = 2, chance = 0.8 },
    }},
    [152816] = { journalMountID = 971, dropsBy = {
        { instanceID = 1712, diff = 17, index = 1, chance = 1.0, lfr = {619, 0.4647, 0.6488, 627}, wing = 1610}, { instanceID = 1712, diff = 14, index = 1, chance = 1.0 },
        { instanceID = 1712, diff = 15, index = 1, chance = 1.0 }, { instanceID = 1712, diff = 16, index = 1, chance = 1.0 }
    }},
    [159842] = { journalMountID = 995, dropsBy = {
        { instanceID = 1754, diff = 23, index = 1, chance = 0.8 },
    }},
    [159921] = { journalMountID = 1040, dropsBy = {
        { instanceID = 1762, diff = 23, index = 1, chance = 0.7 },
    }},
    [160829] = { journalMountID = 1053, dropsBy = {
        { instanceID = 1841, diff = 23, index = 1, chance = 0.7 },
    }},
    [166518] = { journalMountID = 1217, dropsBy = {
        { instanceID = 2070, diff = 17, index = 2, chance = 2.0, lfr = {{1161, 0.7418, 0.135}, {1164, 0.6859, 0.3042}}, wing = {1947, 1950}}, { instanceID = 2070, diff = 14, index = 1, chance = 2.0 },
        { instanceID = 2070, diff = 15, index = 1, chance = 2.0 }, { instanceID = 2070, diff = 16, index = 1, chance = 2.0 }
    }},
    [166705] = { journalMountID = 1219, dropsBy = {
        { instanceID = 2070, diff = 16, index = 2, chance = 0.6 },
    }},
    [168826] = { journalMountID = 1252, dropsBy = {
        { instanceID = 2097, diff = 23, index = 1, chance = 0.7 },
    }},
    [174872] = { journalMountID = 1293, dropsBy = {
        { instanceID = 2217, diff = 16, index = 1, chance = 0.6 },
    }},
    [181819] = { journalMountID = 1406, dropsBy = {
        { instanceID = 2286, diff = 23, index = 1, chance = 0.8 },
    }},
    [186638] = { journalMountID = 1481, dropsBy = {
        { instanceID = 2441, diff = 2, index = 1, chance = 2.0, repeatable = true },
        { instanceID = 2441, diff = 23, index = 1, chance = 2.0 },
    }},
    [186642] = { journalMountID = 1471, dropsBy = {
        { instanceID = 2450, diff = 16, index = 2, chance = 0.4 },
    }},
    [186656] = { journalMountID = 1500, dropsBy = {
        { instanceID = 2450, diff = 17, index = 1, chance = 0.3, lfr = {1670, 0.4163, 0.711}, wing = 2221}, { instanceID = 2450, diff = 14, index = 1, chance = 0.3 },
        { instanceID = 2450, diff = 15, index = 1, chance = 0.3 }, { instanceID = 2450, diff = 16, index = 1, chance = 0.3 }
    }},
    [190768] = { journalMountID = 1587, dropsBy = {
        { instanceID = 2481, diff = 16, index = 1, chance = 0.5 },
    }},
    [210061] = { journalMountID = 1818, dropsBy = {
        { instanceID = 2549, diff = 16, index = 1, chance = 1.0 },
    }},
    [225548] = { journalMountID = 2204, dropsBy = {
        { instanceID = 2651, diff = 23, index = 1, chance = 3.0 },
    }},
    [224147] = { journalMountID = 2219, dropsBy = {
        { instanceID = 2657, diff = 17, index = 1, chance = 0.7, lfr = {2255, 0.4360, 0.8976}, wing = 2651 },
        { instanceID = 2657, diff = 14, index = 1, chance = 0.7 },
        { instanceID = 2657, diff = 15, index = 1, chance = 0.7 },
        { instanceID = 2657, diff = 16, index = 1, chance = 0.7 },
    }},
    [224151] = { journalMountID = 2223, dropsBy = {
        { instanceID = 2657, diff = 16, index = 1, chance = 100.0 },
    }},
    [236960] = { journalMountID = 2507, dropsBy = {
        { instanceID = 2769, diff = 17, index = 1, chance = 0.6, lfr = {2346, 0.4132, 0.4862}, wing = 2783 },
        { instanceID = 2769, diff = 14, index = 1, chance = 0.6 },
        { instanceID = 2769, diff = 15, index = 1, chance = 0.6 },
        { instanceID = 2769, diff = 16, index = 1, chance = 0.6 },
    }},
    [235626] = { journalMountID = 2487, dropsBy = {
        { instanceID = 2769, diff = 16, index = 1, chance = 100.0 }
    }},
    [246445] = { journalMountID = 2606, dropsBy = {
        { instanceID = 2810, diff = 15, index = 1, chance = 100.0 },
        { instanceID = 2810, diff = 16, index = 1, chance = 100.0 }
    }},
    [243061] = { journalMountID = 2569, dropsBy = {
        { instanceID = 2810, diff = 16, index = 1, chance = 100.0 }
    }},

    [13379] = { journalMountID = nil, dropsBy = {
        { instanceID = 329, diff = 1, index = 2, chance = 23.0, repeatable = true }
    }},
    [35275] = { journalMountID = nil, dropsBy = {
        { instanceID = 585, diff = 2, index = 1, chance = 3.0 }
    }},
    [209035] = { journalMountID = nil, dropsBy = {
        --{ instanceID = 2549, diff = 17, index = 2, chance = 79.0 },
        { instanceID = 2549, diff = 14, index = 2, chance = 79.0 },
        { instanceID = 2549, diff = 15, index = 2, chance = 79.0 },
        { instanceID = 2549, diff = 16, index = 2, chance = 79.0 }
    }},
    [236687] = { journalMountID = nil, dropsBy = {
        { instanceID = 2769, diff = 17, index = 2, chance = 83.0, lfr = {2346, 0.4132, 0.4862}, wing = 2781 },
        { instanceID = 2769, diff = 14, index = 2, chance = 83.0 },
        { instanceID = 2769, diff = 15, index = 2, chance = 83.0 },
        { instanceID = 2769, diff = 16, index = 2, chance = 83.0 }
    }},
    [246565] = { journalMountID = nil, dropsBy = {
        { instanceID = 2810, diff = 17, index = 1, chance = 82.0, lfr = {2371, 0.4179, 0.2146}, wing = 2801 },
        { instanceID = 2810, diff = 14, index = 1, chance = 82.0 },
        { instanceID = 2810, diff = 15, index = 1, chance = 82.0 },
        { instanceID = 2810, diff = 16, index = 1, chance = 82.0 }
    }}
}

local instanceToMap = {}
local instanceOrderMap = {}
for i, id in ipairs(db.instanceOrderList) do
    instanceOrderMap[id] = i
end
local serverTime
local charName
local faction

bountyHelper = {}

bountyHelper.difficultyViewData = {}

local ignoreList = {}
local hideIgnored = false
local hideOwned = false
local hideKilled = false
local hideButton = false
local lockEsc = false
local currentScale = 0.85
local searchText = ""
local hideDungeons = false
local hideRaids = false

bountyHelper.frames = {}
bountyHelper.contentFrames = {}
bountyHelper.secondTabFrames = {}

local function findBossByEncounterID(instanceID, encounterID)
    local bossList = db.bossData[instanceID]
    if not bossList then return nil, nil end

    for i, boss in ipairs(bossList) do
        if boss.encounterID == encounterID then
            return boss, i
        end
    end
    return nil, nil
end

local function sharedDifficulty(difficultyID, instanceID, encounterID)
    local sharedGroups = {
        {3, 4, 5, 6}
    }

    local targetGroup
    for _, group in ipairs(sharedGroups) do
        if tContains(group, difficultyID) then
            targetGroup = group
            break
        end
    end

    if not targetGroup then return end

    local boss, bossIndex = findBossByEncounterID(instanceID, encounterID)
    if not boss then return end

    for _, sharedID in ipairs(targetGroup) do
        if sharedID ~= difficultyID and boss.killedAtDiff[sharedID] ~= nil then
            boss.killedAtDiff[sharedID] = true
            if bountyHelper.difficultyViewData[sharedID] and bountyHelper.difficultyViewData[sharedID][instanceID] then
                 for _, cachedBoss in ipairs(bountyHelper.difficultyViewData[sharedID][instanceID]) do
                    if cachedBoss.encounterID == encounterID then
                        cachedBoss.killed = true
                    end
                end
            end
        end
    end
end

local difficultyInfo = {
    [1] = {name = "普通地下城", expanded = false},
    [2] = {name = "英雄地下城", expanded = false},
    [3] = {name = "10人普通团本", expanded = false},
    [4] = {name = "25人普通团本", expanded = false},
    [5] = {name = "10人英雄团本", expanded = false},
    [6] = {name = "25人英雄团本", expanded = false},
    [14] = {name = "普通团本", expanded = false},
    [15] = {name = "英雄团本", expanded = false},
    [16] = {name = "史诗团本", expanded = false},
    [17] = {name = "随机团本", expanded = false},
    [23] = {name = "史诗地下城", expanded = false},
    order = {17, 3, 4, 14, 5, 6, 15, 16, 1, 2, 23},
    dungeons = {[1] = true, [2] = true, [23] = true}
}

local colors = {
    blackRGB = {0.03137, 0.03137, 0.03137}, blackRGBA = {0.03137, 0.03137, 0.03137, 0.825},
    blue = "|cff60b0ff",
    gold = "|cffffd700", goldRGB = {1, 0.7529, 0},
    green = "|cff00ff00",
    grey = "|cffb0b0b0", greyRGB = {0.690196, 0.690196, 0.690196},
    red = "|cffff4040", redRGB = {1, 0.25098, 0.25098},
    white = "|cffffffff", whiteRGB = {1, 1, 1}
}

dbBH = {minimap = {hide = false}}
local buttonBH
local LDB = LibStub("LibDataBroker-1.1"):NewDataObject("BountyHelper",{
  icon = "Interface\\AddOns\\OrzUI\\Media\\Emotes\\exhausted",
  OnClick = function(self,button) if button == "LeftButton" then bountyHelper:Toggle() end end,
  OnTooltipShow = function(tooltip)
    tooltip:AddLine("|cffffffff收集者悬赏助手")
    tooltip:AddLine(colors.green .. "<左键单击打开收集者悬赏助手>")
    tooltip:SetScale(GameTooltip:GetScale())
  end
})

local function createRect(parent, size, point, color, texture, name)
    local f = CreateFrame("Frame", name, parent, "BackdropTemplate")
    f:SetSize(unpack(size))
    f:SetPoint(unpack(point))
    f:SetBackdrop({bgFile = texture or "Interface\\Buttons\\WHITE8x8"})
    if color then f:SetBackdropColor(unpack(color)) end

    return f
end

local function createButton(parent, point, texture, color, onClick, size, tooltip)
    local f = CreateFrame("Button", nil, parent)
    f.color = color
    f:SetSize(unpack(size or {32, 32}))
    f:SetPoint(unpack(point))
    f.texture = f:CreateTexture(nil, "OVERLAY")
    f.texture:SetAllPoints()
    f.texture:SetTexture("Interface\\AddOns\\OrzUI\\Media\\Modules\\BountyHelper\\" .. texture)
    f.texture:SetVertexColor(unpack(color))

    f:SetScript("OnEnter", function()
        f.texture:SetVertexColor(1, 1, 1)
        if tooltip then
            GameTooltip:SetOwner(f, "ANCHOR_LEFT")
            GameTooltip:SetText(tooltip)
            GameTooltip:Show()
        end
    end)
    f:SetScript("OnLeave", function()
        f.texture:SetVertexColor(unpack(f.color))
        if tooltip then GameTooltip_Hide() end
    end)
    f:SetScript("OnClick", onClick)

    function f:setColor(newColor)
        f.color = newColor
        f.texture:SetVertexColor(unpack(newColor))
    end

    return f
end

local function createText(parent, template, point, size, font)
    local f = parent:CreateFontString(nil, "ARTWORK", template)
    if size then f:SetSize(unpack(size)) end
    f:SetPoint(unpack(point))
    if font then f:SetFont(unpack(font)) end

    function f:onEnter(func) f:SetScript("OnEnter", func) end
    function f:onLeave(func) f:SetScript("OnLeave", func) end
    function f:onClick(func)
        f:SetScript("OnMouseDown", function(_, button)
            if button == "LeftButton" then func() end
        end)
    end

    function f:setColor(newColor) f:SetTextColor(unpack(newColor)) end

    return f
end

local function getOrCreatePath(t, ...)
    for _, key in ipairs{...} do
        t[key] = t[key] or {}
        t = t[key]
    end
    return t
end

local function getPath(t, ...)
    for _, key in ipairs{...} do
        if t[key] == nil then return nil end
        t = t[key]
    end
    return t
end

local settingsTimer
function bountyHelper:createUI()
    local settingsPanel

    local f = createRect(UIParent, {650, 900}, ShiGuangDB.BountyHelperpoint, colors.blackRGBA, nil, "收集者悬赏助手")
    f:SetFrameStrata("HIGH")
    f:SetClipsChildren(true)
    f:SetMovable(true)
    f:SetPropagateKeyboardInput(true)
    f:Hide()
    f:SetScript("OnMouseDown", f.StartMoving)
    f:SetScript("OnMouseUp", f.StopMovingOrSizing)
    f:SetScript("OnKeyDown", function(_, key)
        if key == GetBindingKey("TOGGLEGAMEMENU") and not lockEsc then
            f:Hide()
            GameMenuFrame:Show()
        end
    end)
    self.frames.main = f

    local searchBar = CreateFrame("EditBox", "bountyHelperSearchBar", f, "InputBoxTemplate")
    searchBar:SetSize(140, 20)
    searchBar:SetScale(1.2)
    searchBar:SetPoint("TOPRIGHT", -62, -7)
    searchBar:SetAutoFocus(false)
    searchBar:SetTextInsets(5, 5, 0, 0)
    searchBar:SetText(searchText)
    searchBar:SetScript("OnTextChanged", function(self)
        searchText = strtrim(self:GetText()):lower()
        bountyHelper:UpdateVisibleFrame()
    end)
    searchBar:SetScript("OnEnterPressed", function(self)
        self:ClearFocus()
    end)
    self.frames.SearchBar = searchBar
    searchBar:Hide()

    local clearSearchButton = createButton(f, {"RIGHT", searchBar, "RIGHT", -2, 0}, "close", colors.redRGB, function()
        searchText = ""
        searchBar:SetText("")
        bountyHelper:UpdateVisibleFrame()
    end, {24, 24}, "Clear Search")
    clearSearchButton:SetFrameLevel(5)
    self.frames.ClearSearchButton = clearSearchButton
    clearSearchButton:Hide()

    local toMountViewButton = CreateFrame("Button", "bountyHelperToMountViewButton", f, "UIPanelButtonTemplate")
    toMountViewButton:SetPoint("TOPRIGHT", -60, -6)
    toMountViewButton:SetText("按坐骑排序")
    toMountViewButton:SetSize(120, 22)
    toMountViewButton:SetScale(1.2)
    toMountViewButton:SetScript("OnClick", function() bountyHelper:ShowMountView() end)
    bountyHelper.frames.ToMountViewButton = toMountViewButton
    local toDifficultyViewButton = CreateFrame("Button", "bountyHelperToDifficultyViewButton", f, "UIPanelButtonTemplate")
    toDifficultyViewButton:SetPoint("TOPRIGHT", -60, -6)
    toDifficultyViewButton:SetText("按难度排序")
    toDifficultyViewButton:SetSize(120, 22)
    toDifficultyViewButton:SetScale(1.2)

    toDifficultyViewButton:SetScript("OnClick", function() bountyHelper:ShowDifficultyView() end)
    bountyHelper.frames.ToDifficultyViewButton = toDifficultyViewButton
    local diffScrollFrame = CreateFrame("ScrollFrame", "bountyHelperScrollFrame", f, "UIPanelScrollFrameTemplate")
    diffScrollFrame:SetPoint("TOPLEFT", 12, -48)
    diffScrollFrame:SetPoint("BOTTOMRIGHT", -32, 12)
    bountyHelper.frames.ScrollFrame = diffScrollFrame
    local diffScrollChild = CreateFrame("Frame", "bountyHelperScrollChild")
    diffScrollChild:SetSize(f:GetWidth() - 44, 1)
    diffScrollFrame:SetScrollChild(diffScrollChild)
    bountyHelper.frames.ScrollChild = diffScrollChild
    
    local titleText = createText(f, "GameFontNormalHuge", {"TOPLEFT", 12, 0}, {0, 40})
    titleText:SetText(colors.gold .. "收集者悬赏助手")
    local sortingText = createText(f, "GameFontNormal", {"LEFT", titleText, "RIGHT", 12, 0}, nil, {STANDARD_TEXT_FONT, 16})
    sortingText:SetText(colors.gold .. "排序:")
    createButton(f, {"LEFT", sortingText, "RIGHT"}, "expansion", colors.goldRGB, function()
        self:sortContent("default")
    end, nil, "版本")
    createButton(f, {"LEFT", sortingText, "RIGHT", 32, 0}, "chance", colors.goldRGB, function()
        self:sortContent("chance")
    end, nil, "几率")
    createButton(f, {"TOPRIGHT", -36, -4}, "settings", colors.goldRGB, function()
        if settingsTimer then
            settingsTimer:Cancel(); settingsTimer = nil
        end
        settingsPanel:SetShown(not settingsPanel:IsShown())
    end)
    createButton(f, {"TOPRIGHT", -4, -4}, "close", colors.redRGB, function()
        f:Hide()
    end)
    createRect(f, {650, 2}, {"TOP", 0, -40}, colors.goldRGB):SetFrameLevel(10)
    
    local scrollContent = CreateFrame("Frame")
    scrollContent:SetSize(606, 4)
    self.frames.scrollContent = scrollContent
    local scrollFrame = CreateFrame("ScrollFrame", nil, f, "ScrollFrameTemplate")
    scrollFrame:SetPoint("TOPLEFT", 12, -42)
    scrollFrame:SetPoint("BOTTOMRIGHT", -32, 12)
    scrollFrame:SetScrollChild(scrollContent)
    scrollFrame.ScrollBar:ClearAllPoints()
    scrollFrame.ScrollBar:SetHeight(542+300)
    scrollFrame.ScrollBar:SetPoint("TOPRIGHT", 20, -8)
    self.frames.scrollFrame = scrollFrame

    settingsPanel = CreateFrame("Frame", nil, f)
    settingsPanel:SetSize(650, 134)
    settingsPanel:SetPoint("BOTTOM")
    settingsPanel:SetFrameLevel(10)
    settingsPanel:SetClipsChildren(true)
    settingsPanel:EnableMouse(true)
    settingsPanel:Hide()
    settingsPanel:SetScript("OnEnter", function()
        if settingsTimer then
            settingsTimer:Cancel(); settingsTimer = nil
        end
    end)
    settingsPanel:SetScript("OnLeave", function()
        settingsTimer = C_Timer.NewTimer(2, function()
            settingsPanel:Hide(); settingsTimer = nil
        end)
    end)
    createRect(settingsPanel, {650, 32}, {"TOP"}, nil, "Interface\\AddOns\\OrzUI\\Media\\Modules\\BountyHelper\\glow")
    createRect(settingsPanel, {650, 2}, {"TOP", 0, -32}, colors.goldRGB)
    createRect(settingsPanel, {650, settingsPanel:GetHeight() - 34}, {"BOTTOM"}, colors.blackRGB)
    
    local scaleSlider = CreateFrame("Slider", "bountyHelperScaleSlider", settingsPanel, "UISliderTemplate")
    scaleSlider:SetPropagateMouseMotion(true)
    scaleSlider:SetPoint("TOPLEFT", 10, -12-8-2-34)
    scaleSlider:SetWidth(150)
    scaleSlider:SetHeight(22)
    scaleSlider:SetMinMaxValues(0.5, 1.5)
    scaleSlider:SetValueStep(0.05)
    self.frames.ScaleSlider = scaleSlider

    local scaleValueText = scaleSlider:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    scaleValueText:SetFont(STANDARD_TEXT_FONT, 14)
    scaleValueText:SetPoint("LEFT", scaleSlider, "RIGHT", 8, 0)
    self.frames.ScaleValueText = scaleValueText

    scaleSlider:SetScript("OnValueChanged", function(_, value)
        local roundedValue = tonumber(string.format("%.2f", value))
        self.frames.ScaleValueText:SetText(string.format("界面比例: %.2f倍", roundedValue))
    end)

    scaleSlider:SetScript("OnMouseUp", function(self)
        local value = self:GetValue()
        local roundedValue = tonumber(string.format("%.2f", value))
        bountyHelper.frames.main:SetScale(roundedValue)
        currentScale = roundedValue
    end)

    local hideButtonCheckbox = CreateFrame("CheckButton", "bountyHelperHideButtonCheckbox", settingsPanel, "UICheckButtonTemplate")
    hideButtonCheckbox:SetPoint("LEFT", scaleSlider, "RIGHT", 117, 0)
    hideButtonCheckbox:SetPropagateMouseMotion(true)
    hideButtonCheckbox.text = hideButtonCheckbox:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    hideButtonCheckbox.text:SetFont(STANDARD_TEXT_FONT, 14)
    hideButtonCheckbox.text:SetPoint("LEFT", hideButtonCheckbox, "RIGHT", 0, 1)
    hideButtonCheckbox.text:SetText("隐藏按钮")
    hideButtonCheckbox:SetScript("OnClick", function(self)
        hideButton = self:GetChecked()
        buttonBH:SetShown(not hideButton)
        dbBH.minimap.hide = hideButton
    end)
    self.frames.HideButtonCheckbox = hideButtonCheckbox
    
    local hideOwnedCheckbox = CreateFrame("CheckButton", "bountyHelperHideOwnedCheckbox", settingsPanel, "UICheckButtonTemplate")
    hideOwnedCheckbox:SetPropagateMouseMotion(true)
    hideOwnedCheckbox:SetPoint("LEFT", scaleSlider, "RIGHT", 238, 0)
    hideOwnedCheckbox.text = hideOwnedCheckbox:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    hideOwnedCheckbox.text:SetFont(STANDARD_TEXT_FONT, 14)
    hideOwnedCheckbox.text:SetPoint("LEFT", hideOwnedCheckbox, "RIGHT", 0, 1)
    hideOwnedCheckbox.text:SetText("隐藏已拥有")
    hideOwnedCheckbox:SetScript("OnClick", function(self)
        hideOwned = self:GetChecked()
        bountyHelper:UpdateVisibleFrame()
    end)
    self.frames.HideOwnedCheckbox = hideOwnedCheckbox

    local hideKilledCheckbox = CreateFrame("CheckButton", "bountyHelperHideKilledCheckbox", settingsPanel, "UICheckButtonTemplate")
    hideKilledCheckbox:SetPoint("LEFT", scaleSlider, "RIGHT", 365, 0)
    hideKilledCheckbox:SetPropagateMouseMotion(true)
    hideKilledCheckbox.text = hideKilledCheckbox:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    hideKilledCheckbox.text:SetFont(STANDARD_TEXT_FONT, 14)
    hideKilledCheckbox.text:SetPoint("LEFT", hideKilledCheckbox, "RIGHT", 0, 1)
    hideKilledCheckbox.text:SetText("隐藏已击杀")
    hideKilledCheckbox:SetScript("OnClick", function(self)
        hideKilled = self:GetChecked()
        bountyHelper:UpdateVisibleFrame()
    end)
    self.frames.HideKilledCheckbox = hideKilledCheckbox

    local lockCheckbox = CreateFrame("CheckButton", "bountyHelperHideKilledCheckbox", settingsPanel, "UICheckButtonTemplate")
    lockCheckbox:SetPoint("TOPLEFT", settingsPanel, 7, -44-8-2-34)
    lockCheckbox:SetPropagateMouseMotion(true)
    lockCheckbox.text = lockCheckbox:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    lockCheckbox.text:SetFont(STANDARD_TEXT_FONT, 14)
    lockCheckbox.text:SetPoint("LEFT", lockCheckbox, "RIGHT", 0, 1)
    lockCheckbox.text:SetText("禁用ESC关闭窗口")
    lockCheckbox:SetScript("OnClick", function(self)
        lockEsc = self:GetChecked()
    end)
    self.frames.LockCheckbox = lockCheckbox

    local hideIgnoredCheckbox = CreateFrame("CheckButton", "bountyHelperHideIgnoredCheckbox", settingsPanel, "UICheckButtonTemplate")
    hideIgnoredCheckbox:SetPropagateMouseMotion(true)
    hideIgnoredCheckbox:SetPoint("LEFT", lockCheckbox, 184, 0)
    hideIgnoredCheckbox.text = hideIgnoredCheckbox:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    hideIgnoredCheckbox.text:SetFont(STANDARD_TEXT_FONT, 14)
    hideIgnoredCheckbox.text:SetPoint("LEFT", hideIgnoredCheckbox, "RIGHT", 0, 1)
    hideIgnoredCheckbox.text:SetText("隐藏已忽略")
    hideIgnoredCheckbox:SetScript("OnClick", function(self)
        hideIgnored = self:GetChecked()
        bountyHelper:UpdateVisibleFrame()
    end)
    self.frames.HideIgnoredCheckbox = hideIgnoredCheckbox

    local hideDungeonsCheckbox = CreateFrame("CheckButton", "bountyHelperHideDungeonsCheckbox", settingsPanel, "UICheckButtonTemplate")
    hideDungeonsCheckbox:SetPropagateMouseMotion(true)
    hideDungeonsCheckbox:SetPoint("LEFT", hideIgnoredCheckbox, "RIGHT", 104, 0)
    hideDungeonsCheckbox.text = hideDungeonsCheckbox:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    hideDungeonsCheckbox.text:SetFont(STANDARD_TEXT_FONT, 14)
    hideDungeonsCheckbox.text:SetPoint("LEFT", hideDungeonsCheckbox, "RIGHT", 0, 1)
    hideDungeonsCheckbox.text:SetText("Hide Dungeons")
    hideDungeonsCheckbox:SetScript("OnClick", function(self)
        hideDungeons = self:GetChecked()
        bountyHelper:UpdateVisibleFrame()
    end)
    self.frames.HideDungeonsCheckbox = hideDungeonsCheckbox

    local hideRaidsCheckbox = CreateFrame("CheckButton", "bountyHelperHideRaidsCheckbox", settingsPanel, "UICheckButtonTemplate")
    hideRaidsCheckbox:SetPropagateMouseMotion(true)
    hideRaidsCheckbox:SetPoint("LEFT", hideDungeonsCheckbox, "RIGHT", 120, 0)
    hideRaidsCheckbox.text = hideRaidsCheckbox:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    hideRaidsCheckbox.text:SetFont(STANDARD_TEXT_FONT, 14)
    hideRaidsCheckbox.text:SetPoint("LEFT", hideRaidsCheckbox, "RIGHT", 0, 1)
    hideRaidsCheckbox.text:SetText("Hide Raids")
    hideRaidsCheckbox:SetScript("OnClick", function(self)
        hideRaids = self:GetChecked()
        bountyHelper:UpdateVisibleFrame()
    end)
    self.frames.HideRaidsCheckbox = hideRaidsCheckbox
end

function bountyHelper:CreateCategoryHeader(parent, difficultyID)
    local info = difficultyInfo[difficultyID]
    if not info then return nil end

    local header = CreateFrame("Button", nil, parent)
    header:SetSize(parent:GetWidth(), 32)
    header.isCategoryHeader = true
    header.bossRows = {}
    header.difficultyID = difficultyID

    local bg = header:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints(true)
    bg:SetColorTexture(0, 0, 0, 0.9)

    local expander = header:CreateFontString(nil, "ARTWORK", "GameFontNormalLarge")
    expander:SetPoint("LEFT", 10, 0)
    header.expander = expander

    local title = header:CreateFontString(nil, "ARTWORK", "GameFontNormalHuge")
    title:SetPoint("LEFT", expander, "RIGHT", 8, 0)
    title:SetText(colors.blue .. info.name)
    title:SetJustifyH("LEFT")

    header:SetScript("OnClick", function(self)
        info.expanded = not info.expanded
        bountyHelper:UpdateDiffLayout()
    end)
    
    return header
end

function bountyHelper:CreateBossRow(parent, bossData, header, instanceID)
    local row = CreateFrame("Frame", nil, parent)
    row:SetSize(parent:GetWidth() - 20, 52)
    row.bossData = bossData
    row.headerFrame = header
    local data = bossData
    local mapName = instanceToMap[instanceID].name or "Unknown Map"

    local icon = CreateFrame("Button", nil, row)
    icon:SetSize(48, 48)
    icon:SetPoint("LEFT", 5, 0)
    icon:SetNormalTexture(GetItemIcon(data.mountID))
    icon:SetScript("OnEnter", function(self) GameTooltip:SetOwner(self, "ANCHOR_LEFT"); GameTooltip:SetItemByID(data.mountID); GameTooltip:Show() end)
    icon:SetScript("OnLeave", GameTooltip_Hide)
    icon:SetScript("OnClick", function(_, button) if IsControlKeyDown() and not InCombatLockdown() then DressUpMount(data.journalMountID) end end)

    local nameText = row:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    nameText:SetWidth(150)
    nameText:SetWordWrap(false)
    nameText:SetPoint("TOPLEFT", icon, "TOPRIGHT", 14, -10)
    nameText:SetFont(STANDARD_TEXT_FONT, 18, "OUTLINE")
    nameText:SetText(colors.white .. data.name)
    nameText:SetJustifyH("LEFT")
    nameText:EnableMouse(true)
    nameText:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_CURSOR")
        GameTooltip:SetText(data.name)
        GameTooltip:Show()
    end)
    nameText:SetScript("OnLeave", GameTooltip_Hide)
    
    local mapNameText = row:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    mapNameText:SetWidth(150)
    mapNameText:SetWordWrap(false)
    mapNameText:SetPoint("TOPLEFT", nameText, "RIGHT", 8, 0)
    mapNameText:SetFont(STANDARD_TEXT_FONT, 14)
    mapNameText:SetText(colors.blue .. mapName)
    mapNameText:SetJustifyH("LEFT")
    mapNameText:EnableMouse(true)
    mapNameText:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_CURSOR")
        local waypoint = db.waypoints[instanceID]
        GameTooltip:SetText(mapName .. (waypoint and ("\n区域: " .. waypoint.name) or ""))
        GameTooltip:Show()
    end)
    mapNameText:SetScript("OnLeave", GameTooltip_Hide)

    local statusText = row:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    statusText:SetPoint("TOPLEFT", nameText, "BOTTOMLEFT", 0, -3)
    statusText:SetFont(STANDARD_TEXT_FONT, 14)
    statusText:SetJustifyH("LEFT")
    row.statusText = statusText

    local chanceText = row:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    chanceText:SetPoint("RIGHT", -15, 0)
    chanceText:SetFont(STANDARD_TEXT_FONT, 14)
    chanceText:SetJustifyH("RIGHT")
    chanceText:SetFormattedText( "概率：%s%s|r -> %s%.2f%%|r", colors.grey, (data.chance == 0) and "未知" or string.format("%.2f%%", data.chance), colors.green, data.chance + 5.0)
    
    return row
end

function bountyHelper:GenerateDifficultyViewData()
    local result = {}
    for mountID, mount in pairs(db.mountData) do
        for _, drop in ipairs(mount.dropsBy) do
            local diff = drop.diff
            local inst = drop.instanceID
            local bossInfo = db.bossData[inst][drop.index]

            if not result[diff] then result[diff] = {} end
            if not result[diff][inst] then result[diff][inst] = {} end

            local isKilled = bossInfo.killedAtDiff[diff]

            local entry = {
                name = bossInfo.name,
                encounterID = bossInfo.encounterID,
                killed = isKilled,
                mountID = mountID,
                journalMountID = mount.journalMountID,
                chance = drop.chance,
                lfr = drop.lfr,
                repeatable = drop.repeatable or false
            }
            table.insert(result[diff][inst], entry)
        end
    end
    self.difficultyViewData = result
end

function bountyHelper:PopulateList()
    local scrollChild = bountyHelper.frames.ScrollChild
    
    for _, frame in ipairs(bountyHelper.secondTabFrames) do
        frame:Hide()
    end
    wipe(bountyHelper.secondTabFrames)

    local dataForView = self.difficultyViewData

    for _, difficultyID in ipairs(difficultyInfo.order) do
        local diffData = dataForView[difficultyID]
        local info = difficultyInfo[difficultyID]

        if diffData and info then
            local header = bountyHelper:CreateCategoryHeader(scrollChild, difficultyID)
            table.insert(bountyHelper.secondTabFrames, header)

            local sortedInstanceIDs = {}
            for instanceID in pairs(diffData) do
                table.insert(sortedInstanceIDs, instanceID)
            end

            table.sort(sortedInstanceIDs, function(a, b)
                local orderA = instanceOrderMap[a] or 9999
                local orderB = instanceOrderMap[b] or 9999
                return orderA < orderB
            end)

            for _, instanceID in ipairs(sortedInstanceIDs) do
                local bossList = diffData[instanceID]
                for _, bossEntryData in ipairs(bossList) do
                    local row = bountyHelper:CreateBossRow(scrollChild, bossEntryData, header, instanceID)
                    table.insert(header.bossRows, row)
                    table.insert(bountyHelper.secondTabFrames, row)
                end
            end
        end
    end
end

function bountyHelper:filterContent(name, search)
    if search == "" then return true end
    return name:lower():find(search, 1, true) ~= nil
end

function bountyHelper:UpdateDiffLayout()
    local scrollChild = bountyHelper.frames.ScrollChild
    local lastVisibleFrame = nil
    local totalHeight = 0
    local yPadding = 4
    local xIndent = 20

    for _, frame in ipairs(bountyHelper.secondTabFrames) do
        local isVisible = true
        if frame.isCategoryHeader then
            local info = difficultyInfo[frame.difficultyID]
            frame.expander:SetText(info.expanded and "-" or "+")
            frame.childCount = 0
            if hideDungeons and difficultyInfo.dungeons[frame.difficultyID] then
                isVisible = false
            elseif hideRaids and not difficultyInfo.dungeons[frame.difficultyID] then
                isVisible = false
            end
        else
            local data = frame.bossData 
            local header = frame.headerFrame
            local categoryInfo = difficultyInfo[header.difficultyID]
            if not categoryInfo.expanded then isVisible = false end
            
            local journalMountID = data.journalMountID
            local isOwned = journalMountID and select(11, C_MountJournal.GetMountInfoByID(data.journalMountID)) or PlayerHasToy(data.mountID)
            
            if isVisible and hideOwned and isOwned then
                isVisible = false
            end
            if isVisible and hideKilled and data.killed and not isOwned and not data.repeatable then
                isVisible = false
            end
            if isVisible and hideDungeons and difficultyInfo.dungeons[header.difficultyID] then
                isVisible = false
            end
            if isVisible and hideRaids and not difficultyInfo.dungeons[header.difficultyID] then
                isVisible = false
            end

            if not ((hideKilled and data.killed and not isOwned and not data.repeatable) or (hideOwned and isOwned)) then
                 header.childCount = header.childCount + 1
            end

            if isOwned then
                frame.statusText:SetText(colors.gold .. "已拥有")
            elseif data.repeatable then
                frame.statusText:SetText(colors.gold .. "Repeatable")
            else
                frame.statusText:SetText(data.killed and (colors.green .. "已击杀") or (colors.red .. "未击杀"))
            end
        end
        frame:SetShown(isVisible)
    end

    for _, frame in ipairs(bountyHelper.secondTabFrames) do
        if frame.isCategoryHeader and frame.childCount == 0 then frame:Hide() end
        if frame:IsShown() then
            frame:ClearAllPoints()
            if not lastVisibleFrame then
                frame:SetPoint("TOP", scrollChild, "TOP", 0, 0)
            else
                frame:SetPoint("TOP", lastVisibleFrame, "BOTTOM", 0, -yPadding)
            end

            if frame.isCategoryHeader then
                frame:SetPoint("LEFT", scrollChild, "LEFT", 0, 0)
            else
                frame:SetPoint("LEFT", scrollChild, "LEFT", xIndent, 0)
            end
            
            lastVisibleFrame = frame
            totalHeight = totalHeight + frame:GetHeight() + yPadding
        end
    end

    scrollChild:SetHeight(math.max(1, totalHeight - yPadding + 10))
end

function bountyHelper:GetUnsortedMountCentricData()
    local mountCentricData = {}
    for mountID, mount in pairs(db.mountData) do
        mountCentricData[mountID] = { sources = {}, journalMountID = mount.journalMountID }
        for _, drop in ipairs(mount.dropsBy) do
            local bossInfo = db.bossData[drop.instanceID][drop.index]
            local isKilled = bossInfo.killedAtDiff[drop.diff]

            local combinedData = {
                name = bossInfo.name,
                encounterID = bossInfo.encounterID,
                killed = isKilled,
                mountID = mountID,
                journalMountID = mount.journalMountID,
                chance = drop.chance,
                lfr = drop.lfr
            }

            table.insert(mountCentricData[mountID].sources, {
                difficultyID = drop.diff,
                instanceID = drop.instanceID,
                bossIndex = drop.index,
                originalData = combinedData
            })
        end
    end

    local orderMap = {}
    for i, id in ipairs(difficultyInfo.order) do
        orderMap[id] = i
    end

    for mountID, data in pairs(mountCentricData) do
        table.sort(data.sources, function(a, b)
            return (orderMap[a.difficultyID] or 999) < (orderMap[b.difficultyID] or 999)
        end)
    end
    
    return mountCentricData
end

function bountyHelper:loadMountData(callback)
    local pending = 59

    for mountID, data in pairs(db.mountData) do
        local item = Item:CreateFromItemID(mountID)
        item:ContinueOnItemLoad(function()
            data.name = item:GetItemName()
            pending = pending - 1
            if pending == 0 then callback() end
        end)
    end
end

function bountyHelper:createContent()
    for mountID, data in pairs(db.mountData) do
        local headerRow = self:createHeaderRow(mountID, data.journalMountID, db.mountData[mountID].name, data.dropsBy[1].chance)
        
        local children = {
            [headerRow.ignore] = 1,
            [headerRow.arrow] = 1
        }
        local instanceID = data.dropsBy[1].instanceID
        local mountLink = select(2, GetItemInfo(mountID))

        headerRow.border:SetScript("OnEnter", function(self)
            self:SetAlpha(1)
            headerRow.arrow:Show()
            GameTooltip:SetOwner(self, "ANCHOR_CURSOR")
                GameTooltip:SetText(colors.green .. "<左键单击添加地图标记>");
            GameTooltip:Show()
        end)
        headerRow.border:SetScript("OnLeave", function(self)
            if not children[GetMouseFoci()[1]] then
                self:SetAlpha(0)
                headerRow.arrow:Hide()
            end
            GameTooltip_Hide()
        end)
        headerRow.arrow:HookScript("OnLeave", function(self)
            headerRow.border:SetAlpha(0)
            self:Hide()
        end)
        headerRow.border:SetScript("OnMouseDown", function()
            if IsControlKeyDown() then
                if not InCombatLockdown() then DressUpMount(data.journalMountID) end
            elseif db.waypoints[instanceID] then
                if not InCombatLockdown() then
                    local waypoint = UiMapPoint.CreateFromCoordinates(unpack(db.waypoints[instanceID].point))
                    C_Map.SetUserWaypoint(waypoint)
                    C_SuperTrack.SetSuperTrackedUserWaypoint(true)
                    C_Map.OpenWorldMap(db.waypoints[instanceID].point[4] or db.waypoints[instanceID].point[1])
                    print(string.format("%s收集者悬赏助手：|r已为%s设置导航点", colors.gold, mountLink))
                end
            else
                    print(string.format("%s收集者悬赏助手：|r%s暂无可用的位置数据", colors.gold, mountLink))
            end
        end)
        table.insert(self.contentFrames, headerRow)
        
        for _, source in ipairs(data.dropsBy) do
            local sourceRow = self:createSourceRow(source)
            table.insert(headerRow.sourceRows, sourceRow)
            table.insert(self.contentFrames, sourceRow)
        end
    end
end

function bountyHelper:createHeaderRow(mountID, journalMountID, name, chance)
    local row = CreateFrame("Frame", nil, self.frames.scrollContent)
    row:SetSize(606, 56)
    row:SetClipsChildren(true)
    row.isHeader = true
    row.sourceRows = {}
    row.mountID = mountID
    
    local color = ignoreList[mountID] and colors.redRGB or colors.goldRGB

    local panel = createRect(row, {602, 36}, {"TOP", 0, -2}, colors.blackRGB)
    panel:SetFrameLevel(3)
    local border = createRect(row, {606, 40}, {"TOP"}, color)
    border:SetFrameLevel(2)
    border:SetAlpha(0)
    row.border = border

    local icon = CreateFrame("Button", nil, panel)
    icon:SetSize(36, 36)
    icon:SetPoint("TOPLEFT")
    icon:SetNormalTexture(GetItemIcon(mountID))
    icon:GetNormalTexture():SetTexCoord(0.0625, 0.9375, 0.0625, 0.9375)
    icon:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_LEFT")
        GameTooltip:SetItemByID(mountID)
        GameTooltip:Show()
    end)
    icon:SetScript("OnLeave", GameTooltip_Hide)
    icon:SetScript("OnClick", function()
        if IsControlKeyDown() and not InCombatLockdown() then
            DressUpMount(journalMountID)
        end
    end)
    createText(panel, "GameFontNormalLarge", {"TOPLEFT", 48, -10}):SetText(name)
    local chanceText = createText(panel, "GameFontNormal", {"TOPRIGHT", -12, -10}, nil, {STANDARD_TEXT_FONT, 14})
    chanceText:SetJustifyH("RIGHT")
    chanceText:SetFormattedText( "概率：%s%s|r > %s%.1f%%|r", colors.grey, (chance == 0) and "未知" or string.format("%.1f%%", chance), colors.green, chance + 5)
    
    local ignore = createButton(panel, {"TOPLEFT", 2, -38}, "ignore", colors.redRGB, function()
        ignoreList[mountID] = not ignoreList[mountID]
        local newColor = ignoreList[mountID] and colors.redRGB or colors.goldRGB
        border:SetBackdropColor(unpack(newColor))
        row.arrow:setColor(newColor)
        self:updateContent()
    end, nil, "Ignore")
    ignore:Hide()
    row.ignore = ignore

    row.expanded = false
    row.arrow = createButton(row, {"BOTTOM"}, "arrow", color, function()
        row.expanded = not row.expanded
        local height = row.expanded and 92 or 56

        row:SetHeight(height)
        panel:SetHeight(height - 20)
        border:SetHeight(height - 16)
        row.arrow.texture:SetTexCoord(unpack(row.expanded and {1, 0, 1, 0} or {0, 1, 0, 1}))
        ignore:SetShown(row.expanded)
    end)
    row.arrow:Hide()

    return row
end

function bountyHelper:createSourceRow(source)
    local row = CreateFrame("Frame", nil, self.frames.scrollContent)
    row:SetSize(606, 30)
    row:SetClipsChildren(true)
    row.source = source

    local nameText = createText(row, "GameFontNormal", {"LEFT", 12, 0}, nil, {STANDARD_TEXT_FONT, 16})
    nameText:SetWordWrap(false)
    nameText:SetText(colors.white .. db.bossData[source.instanceID][source.index].name)
    nameText:SetSize(math.min(nameText:GetWidth(), 180), 30)
    nameText:SetScript("OnEnter", function(self)
        GameTooltip:SetOwner(self, "ANCHOR_CURSOR")
        GameTooltip:SetText(db.bossData[source.instanceID][source.index].name)
        GameTooltip:Show()
    end)
    nameText:SetScript("OnLeave", GameTooltip_Hide)
    --
    local mapNameText = createText(row, "GameFontNormal", {"LEFT", nameText, "RIGHT", 6, 0}, nil, {STANDARD_TEXT_FONT, 14})
    mapNameText:SetWordWrap(false)
    mapNameText:SetText(colors.blue .. instanceToMap[source.instanceID].name)
    mapNameText:SetSize(math.min(mapNameText:GetWidth(), 180), 30)
    mapNameText:SetScript("OnEnter", function(self)
        local waypoint = db.waypoints[source.instanceID]
        GameTooltip:SetOwner(self, "ANCHOR_CURSOR")
        GameTooltip:SetText(instanceToMap[source.instanceID].name .. (waypoint and ("\n区域: " .. waypoint.name) or ""))
        GameTooltip:Show()
    end)
    mapNameText:SetScript("OnLeave", GameTooltip_Hide)
    --
    local diffText = createText(row, "GameFontNormal", {"LEFT", mapNameText, "RIGHT", 6, 0}, nil, {STANDARD_TEXT_FONT, 14})
    diffText:setColor(colors.greyRGB)
    diffText:SetText(difficultyInfo[source.diff].name)
    diffText:SetHeight(30)
    --
    local statusText = createText(row, "GameFontNormal", {"RIGHT", -12, 0}, nil, {STANDARD_TEXT_FONT, 14})
    statusText:SetHeight(30)
    statusText:SetJustifyH("RIGHT")
    statusText:onEnter(function(self)
        local tooltip = ""
        for name, data in pairs(ShiGuangDB.BountyHelperaltData) do
            if name ~= charName then
                local reset = getPath(data, source.instanceID, source.index, source.diff)
                if reset and GetServerTime() - reset < 0 then
                    tooltip = string.format("%s\n|c%s%s", tooltip, RAID_CLASS_COLORS[data["CLASS"]].colorStr, name)
                end
            end
        end
        if #tooltip > 0 then
            GameTooltip:SetOwner(self, "ANCHOR_CURSOR")
            GameTooltip:SetText(string.format("%sKilled on:%s", colors.green, tooltip))
            GameTooltip:Show()
        end
    end)
    statusText:onLeave(GameTooltip_Hide)
    row.statusText = statusText

    if source.lfr then
        if type(source.lfr[1]) == "table" then
            source.lfr = source.lfr[faction]
        end
        if type(source.wing) == "table" then
            source.wing = source.wing[faction]
        end
        createButton(row, {"LEFT", diffText, "RIGHT"}, "pin", colors.goldRGB, function()
            if not InCombatLockdown() then
                C_Map.SetUserWaypoint(UiMapPoint.CreateFromCoordinates(unpack(source.lfr)))
                C_SuperTrack.SetSuperTrackedUserWaypoint(true)
                C_Map.OpenWorldMap(source.lfr[4] or source.lfr[1])
                print(string.format("%sBounty Helper:|r Waypoint set", colors.gold))
            end
        end, nil, colors.green .. "<Left Click to add Map Pin>|r\nWing: " .. GetLFGDungeonInfo(source.wing))
    else
        local underline = createRect(row, {diffText:GetWidth(), 2}, {"BOTTOM", diffText}, colors.goldRGB)
        underline:Hide()
        diffText:onEnter(function(self) self:setColor(colors.whiteRGB); underline:Show() end)
        diffText:onLeave(function(self) self:setColor(colors.greyRGB); underline:Hide() end)
        diffText:onClick(function()
            ((difficultyInfo.dungeons[source.diff] and SetDungeonDifficultyID) or (IsLegacyDifficulty(source.diff) and SetLegacyRaidDifficultyID) or SetRaidDifficultyID)(source.diff)
        end)
    end

    return row
end

local lastSorting
local sortingWay = false --Ascending
function bountyHelper:sortContent(sorting)
    if lastSorting == sorting then sortingWay = not sortingWay
    else
        lastSorting = sorting
        sortingWay = false
    end
    
    local defaultOrder = {
        13335, 13379, 30480, 32458, 32768, 35513, 35275, 43952, 
        43953, 43959, 44151, 45693, 49636, 50818, 63040, 63041,
        63043, 68823, 68824, 69224, 71665, 77067, 77069, 78919,
        87777, 93666, 95059, 104253, 116660, 123890, 137574, 137575,
        142236, 143643, 152789, 152816, 159842, 159921, 160829, 166518,
        166705, 168826, 174872, 181819, 186638, 186656, 186642, 190768,
        210061, 209035, 225548, 224147, 224151, 236960, 235626, 236687,
        246445, 243061, 246565
    }
    local orderMap = {}
    for i, id in ipairs(defaultOrder) do orderMap[id] = i end

    local currentGroup
    local groupedFrames = {}
    for _, frame in ipairs(self.contentFrames) do
        if frame.isHeader then
            currentGroup = {frame}
            table.insert(groupedFrames, currentGroup)
        else table.insert(currentGroup, frame) end
    end

    table.sort(groupedFrames, function(a, b)
        if sortingWay then local c = a; a = b; b = c end
        if sorting == "default" then
            return orderMap[a[1].mountID] < orderMap[b[1].mountID]
        elseif sorting == "chance" then
            local chanceA = a[2].source.chance
            local chanceB = b[2].source.chance

            if chanceA == chanceB then return orderMap[a[1].mountID] < orderMap[b[1].mountID]
            else return chanceA < chanceB end
        end
    end)

    self.contentFrames = {}
    for _, group in ipairs(groupedFrames) do
        for _, element in ipairs(group) do
            table.insert(self.contentFrames, element)
        end
    end

    self:updateContent()
end

function bountyHelper:updateContent()
    for _, frame in ipairs(self.contentFrames) do
        if frame.isHeader then
            local journalMountID = db.mountData[frame.mountID].journalMountID
            local isOwned = journalMountID and select(11, C_MountJournal.GetMountInfoByID(journalMountID)) or PlayerHasToy(frame.mountID)
            local sourceCount = 0

            for _, sourceRow in ipairs(frame.sourceRows) do
                local source = sourceRow.source
                local boss = db.bossData[source.instanceID][source.index]
                local killed = boss.killedAtDiff[source.diff]

                if isOwned then
                    sourceRow.statusText:SetText(colors.gold .. "已拥有")
                elseif source.repeatable then
                    sourceRow.statusText:SetText(colors.gold .. "Repeatable")
                else
                    sourceRow.statusText:SetText(killed and (colors.green .. "已击杀") or (colors.red .. "未击杀"))
                end

                local hide = (hideIgnored and ignoreList[frame.mountID]) or (hideOwned and isOwned) or (hideKilled and killed and not isOwned and not source.repeatable)
                if not hide and searchText ~= "" then
                    hide = not self:filterContent(db.mountData[frame.mountID].name, searchText)
                end
                if not hide and hideDungeons and difficultyInfo.dungeons[source.diff] then
                    hide = true
                end
                if not hide and hideRaids and not difficultyInfo.dungeons[source.diff] then
                    hide = true
                end
                if not hide then sourceCount = sourceCount + 1 end
                sourceRow:SetShown(not hide)
            end
            
            frame:SetShown(sourceCount ~= 0)
        end
    end
    
    local lastFrame = nil
    for _, frame in ipairs(self.contentFrames) do
        if frame:IsShown() then
            frame:ClearAllPoints()
            if not lastFrame then frame:SetPoint("TOP", self.frames.scrollContent, "BOTTOM")
            else frame:SetPoint("TOP", lastFrame, "BOTTOM", 0, lastFrame.isHeader and 12 or -4) end
            lastFrame = frame
        end
    end
end

function bountyHelper:initialize()
    self:createUI()
    self:loadMountData(function()
        self:createContent()
        self:sortContent("default")
    end)

    self:GenerateDifficultyViewData() 
    self:PopulateList()
end

function bountyHelper:ShowDifficultyView()
    bountyHelper.frames.ScrollFrame:Show()
    bountyHelper.frames.ToMountViewButton:Show()
    
    bountyHelper.frames.scrollFrame:Hide()
    bountyHelper.frames.ToDifficultyViewButton:Hide()
    
    bountyHelper.frames.SearchBar:Hide()
    bountyHelper.frames.ClearSearchButton:Hide()
    
    bountyHelper:UpdateDiffLayout()
    bountyHelper.frames.main:Show()
end

function bountyHelper:ShowMountView()
    bountyHelper.frames.ScrollFrame:Hide()
    bountyHelper.frames.ToMountViewButton:Hide()

    bountyHelper.frames.scrollFrame:Show()
    bountyHelper.frames.ToDifficultyViewButton:Show()
    
    bountyHelper.frames.SearchBar:Show()
    bountyHelper.frames.ClearSearchButton:Show()
    
    bountyHelper:updateContent()
    bountyHelper.frames.main:Show()
end

function bountyHelper:Toggle()
    if bountyHelper.frames.main:IsShown() then
        bountyHelper.frames.main:Hide()
    else
        bountyHelper:UpdateDiffLayout()
        bountyHelper:updateContent()
        
        bountyHelper.frames.HideIgnoredCheckbox:SetChecked(hideIgnored)
        bountyHelper.frames.HideOwnedCheckbox:SetChecked(hideOwned)
        bountyHelper.frames.HideKilledCheckbox:SetChecked(hideKilled)
        bountyHelper.frames.HideButtonCheckbox:SetChecked(hideButton)
        bountyHelper.frames.LockCheckbox:SetChecked(lockEsc)
        bountyHelper.frames.HideDungeonsCheckbox:SetChecked(hideDungeons)
        bountyHelper.frames.HideRaidsCheckbox:SetChecked(hideRaids)
        bountyHelper.frames.SearchBar:SetText(searchText)
        bountyHelper:ShowMountView()
    end
end

function bountyHelper:UpdateVisibleFrame()
    if bountyHelper.frames.ScrollFrame:IsShown() then
        bountyHelper:UpdateDiffLayout()
    elseif bountyHelper.frames.scrollFrame:IsShown() then
        bountyHelper:updateContent()
    end
end

local function checkSaved()
    local savedData = {}
    for i = 1, GetNumSavedInstances() do
        local reset, difficultyID, _, _, _, _, _, _, _, _, _, instanceID = select(3, GetSavedInstanceInfo(i))
        if reset ~= 0 then
            local bossList = db.bossData[instanceID]
            if bossList then
                for j, boss in ipairs(bossList) do
                    if boss.killedAtDiff[difficultyID] ~= nil then
                        if C_RaidLocks.IsEncounterComplete(instanceID, boss.encounterID, difficultyID) then
                            getOrCreatePath(savedData, instanceID, j)[difficultyID] = serverTime + reset

                            local connectedDifficulties = {3, 4, 5, 6}
                            if tContains(connectedDifficulties, difficultyID) then
                                for _, diff in ipairs(connectedDifficulties) do
                                    if diff ~= difficultyID and boss.killedAtDiff[diff] ~= nil then
                                        getOrCreatePath(savedData, instanceID, j)[diff] = serverTime + reset
                                    end
                                end
                            end
                            
                            boss.killedAtDiff[difficultyID] = true
                            if bountyHelper.difficultyViewData[difficultyID] and bountyHelper.difficultyViewData[difficultyID][instanceID] then
                                for _, cachedBoss in ipairs(bountyHelper.difficultyViewData[difficultyID][instanceID]) do
                                    if cachedBoss.encounterID == boss.encounterID then
                                        cachedBoss.killed = true
                                    end
                                end
                            end
                            sharedDifficulty(difficultyID, instanceID, boss.encounterID)
                        end
                    end
                end
            end
        end
    end
    if next(savedData) then
        savedData["CLASS"] = select(2, UnitClass("player"))
        ShiGuangDB.BountyHelperaltData[charName] = savedData
    end
end

local eventHandlerFrame = CreateFrame("Frame")
eventHandlerFrame:RegisterEvent("ADDON_LOADED")
eventHandlerFrame:RegisterEvent("FIRST_FRAME_RENDERED")
eventHandlerFrame:RegisterEvent("PLAYER_LOGOUT")
eventHandlerFrame:RegisterEvent("ENCOUNTER_END")

eventHandlerFrame:SetScript("OnEvent", function(self, event, ...)
    if event == "ADDON_LOADED" then
        if ... == "OrzUI" then
            ignoreList = ShiGuangDB.BountyHelperignoreList or {}
            hideIgnored = ShiGuangDB.BountyHelperhideIgnored or false
            hideOwned = ShiGuangDB.BountyHelperhideOwned or false
            hideKilled = ShiGuangDB.BountyHelperhideKilled or false
            hideButton = ShiGuangDB.BountyHelperhideButton or false
            lockEsc = ShiGuangDB.BountyHelperlockEsc or false
            hideDungeons = ShiGuangDB.hideDungeons or false
            hideRaids = ShiGuangDB.hideRaids or false
            currentScale = ShiGuangDB.BountyHelperscale or 1.0
            searchText = ShiGuangDB.searchText or ""
            ShiGuangDB.BountyHelperpoint = ShiGuangDB.BountyHelperpoint or {"CENTER", 0, 0}
            ShiGuangDB.BountyHelperaltData = ShiGuangDB.BountyHelperaltData or {}

            local LibDBIcon = LibStub("LibDBIcon-1.0")
            LibDBIcon:Register("BountyHelper", LDB, dbBH.minimap)
            buttonBH = LibDBIcon:GetMinimapButton("BountyHelper")
        end
    
    elseif event == "FIRST_FRAME_RENDERED" then
        serverTime = GetServerTime()
        charName = string.format("%s-%s", GetUnitName("player"), GetRealmName())
        faction = (UnitFactionGroup("player") == "Alliance") and 1 or 2

        for i, wp in pairs(db.waypoints) do
            if type(wp.point[1]) == "table" then
                wp.point = i == 2217 and wp.point[(#C_EncounterJournal.GetDungeonEntrancesForMap(1527) > 6) and 1 or 2] or wp.point[faction]
            end
            wp.name = C_Map.GetMapInfo(wp.point[1]).name
        end

        local journalOverrides = {[329] = 1292}
        local difficultyOverrides = {[556] = 2}
        for _, id in ipairs(db.instanceOrderList) do
            local journalID = journalOverrides[id] or C_EncounterJournal.GetInstanceForGameMap(id)
            local name = EJ_GetInstanceInfo(journalID)
            instanceToMap[id] = {
                journalID = journalID,
                name = name,
                difficultyID = difficultyOverrides[id] or nil
            }
        end

        for instanceID, bosses in pairs(db.bossData) do
            for _, boss in ipairs(bosses) do
                local ejIndex = boss.encounterID
                boss.name, _, _, _, _, _, boss.encounterID = EJ_GetEncounterInfo(ejIndex)
            end
        end

        bountyHelper:initialize()
        bountyHelper.frames.main:SetScale(currentScale)
        bountyHelper.frames.ScaleSlider:SetValue(currentScale)
        bountyHelper.frames.ScaleValueText:SetText(string.format("界面比例: %.2f", currentScale))

        checkSaved()

        SLASH_CBH1 = "/bh"
        SLASH_CBH2 = "/cbh"
        SLASH_CBH3 = "/bounty"
        SLASH_CBH4 = "/bountyhelper"
        SlashCmdList["CBH"] = function() bountyHelper:Toggle() end
        self:UnregisterEvent("FIRST_FRAME_RENDERED")
        self:UnregisterEvent("ADDON_LOADED")

    elseif event == "PLAYER_LOGOUT" then
        ShiGuangDB.BountyHelperignoreList = ignoreList
        ShiGuangDB.BountyHelperhideIgnored = hideIgnored
        ShiGuangDB.BountyHelperhideOwned = hideOwned
        ShiGuangDB.BountyHelperhideKilled = hideKilled
        ShiGuangDB.BountyHelperhideButton = hideButton
        ShiGuangDB.BountyHelperlockEsc = lockEsc
        ShiGuangDB.hideDungeons = hideDungeons
        ShiGuangDB.hideRaids = hideRaids
        ShiGuangDB.BountyHelperscale = currentScale
        ShiGuangDB.searchText = searchText
        local point, relativeTo, relativePoint, xOfs, yOfs = bountyHelper.frames.main:GetPoint()
        ShiGuangDB.BountyHelperpoint = { relativePoint, xOfs, yOfs }
        checkSaved()

    elseif event == "ENCOUNTER_END" then
        local encounterID, _, difficultyID, _, success = ...
        if success == 1 then
            local instanceID = select(8, GetInstanceInfo())
            local boss, bossIndex = findBossByEncounterID(instanceID, encounterID)
            
            if boss and boss.killedAtDiff[difficultyID] ~= nil then
                boss.killedAtDiff[difficultyID] = true
                
                if bountyHelper.difficultyViewData[difficultyID] and bountyHelper.difficultyViewData[difficultyID][instanceID] then
                     for _, cachedBoss in ipairs(bountyHelper.difficultyViewData[difficultyID][instanceID]) do
                        if cachedBoss.encounterID == encounterID then
                            cachedBoss.killed = true
                        end
                    end
                end

                sharedDifficulty(difficultyID, instanceID, encounterID)

                if bountyHelper.frames.main:IsShown() then
                    bountyHelper:UpdateDiffLayout()
                    bountyHelper:updateContent()
                end

                RequestRaidInfo()
            end
        end
    end
end)