--[[ Encounter history. Catalogued rares open their complete field dossier. ]]

local _, ns = ...

local SightingsPanel = ns.NewModule("SightingsPanel")
ns.UI = ns.UI or {}
ns.UI.SightingsPanel = SightingsPanel

local SEEN_COLOR = { r = 0.28, g = 0.86, b = 0.78 }
local CAPTURED_COLOR = { r = 0.35, g = 0.95, b = 0.62 }
local KILLED_COLOR = { r = 0.96, g = 0.38, b = 0.24 }
local BOTH_COLOR = { r = 1.00, g = 0.76, b = 0.24 }
local UNKNOWN_COLOR = { r = 0.66, g = 0.56, b = 0.43 }
local Theme = ns.UI.Theme

local function MapName(mapID)
    local info = mapID and C_Map and C_Map.GetMapInfo and C_Map.GetMapInfo(mapID)
    return info and info.name or ns.L["DETAIL_ZONE_UNKNOWN"]
end

local function OutcomePresentation(npcID)
    local outcome = ns.Collection.RareState:GetOutcome(npcID)
    if outcome == "both" then
        return ns.L["RARE_CATALOG_CAPTURED_AND_KILLED"], BOTH_COLOR, true
    elseif outcome == "captured" then
        return ns.L["RARE_CATALOG_CAPTURED"], CAPTURED_COLOR, true
    elseif outcome == "killed" then
        return ns.L["RARE_CATALOG_KILLED"], KILLED_COLOR, true
    end
    return nil, SEEN_COLOR, false
end

function SightingsPanel:Create(parent)
    local panel = { recordsByKey = {} }
    local frame = CreateFrame("Frame", nil, parent)
    frame:SetAllPoints(parent)
    panel.frame = frame

    -- A compact field-radio strip: alert scope is a hunting preference, not a
    -- list filter, so it stays above the encounter history it governs.
    local alertBar = Theme:CreatePanel(frame, Theme.color.panelSoft,
        Theme.color.line)
    alertBar:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, 0)
    alertBar:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, 0)
    alertBar:SetHeight(54)

    local signal = alertBar:CreateTexture(nil, "ARTWORK")
    signal:SetSize(9, 9)
    signal:SetPoint("LEFT", alertBar, "LEFT", 16, 0)
    signal:SetRotation(math.pi / 4)
    signal:SetColorTexture(Theme.color.tracker[1], Theme.color.tracker[2],
        Theme.color.tracker[3], 1)

    local alertTitle = alertBar:CreateFontString(nil, "ARTWORK", "GameFontNormal")
    alertTitle:SetPoint("TOPLEFT", alertBar, "TOPLEFT", 34, -8)
    alertTitle:SetText(ns.L["ALERT_SCOPE_TITLE"])
    alertTitle:SetTextColor(Theme.color.gold[1], Theme.color.gold[2],
        Theme.color.gold[3])

    local alertHint = alertBar:CreateFontString(nil, "ARTWORK",
        "GameFontHighlightSmall")
    alertHint:SetPoint("TOPLEFT", alertTitle, "BOTTOMLEFT", 0, -3)
    alertHint:SetText(ns.L["ALERT_SCOPE_HINT"])
    alertHint:SetTextColor(Theme.color.muted[1], Theme.color.muted[2],
        Theme.color.muted[3])

    local scopeButtons = {}
    local function CreateScopeButton(scope, text, width)
        local button = CreateFrame("Button", nil, alertBar, "BackdropTemplate")
        button:SetSize(width, 30)
        button:SetNormalFontObject(GameFontNormalSmall)
        button:SetText(text)
        button.scope = scope
        button:SetScript("OnClick", function()
            ns.Config:Set("alertScope", scope)
        end)
        scopeButtons[#scopeButtons + 1] = button
        return button
    end

    local catalogScope = CreateScopeButton("catalog",
        ns.L["ALERT_SCOPE_CATALOG"], 174)
    catalogScope:SetPoint("RIGHT", alertBar, "RIGHT", -190, 0)
    local allScope = CreateScopeButton("all", ns.L["ALERT_SCOPE_ALL"], 174)
    allScope:SetPoint("LEFT", catalogScope, "RIGHT", 6, 0)

    local function RefreshAlertScope()
        local selected = ns.Config:Get("alertScope") == "all" and "all" or "catalog"
        for _, button in ipairs(scopeButtons) do
            Theme:ApplyButton(button, button.scope == selected)
        end
    end
    panel.RefreshAlertScope = RefreshAlertScope

    local listHost = CreateFrame("Frame", nil, frame)
    listHost:SetPoint("TOPLEFT", alertBar, "BOTTOMLEFT", 0, -8)
    listHost:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, 0)

    panel.list = ns.UI.PetList:Create(listHost, {
        onSelect = function(key)
            local npcID = panel.recordsByKey[key]
            if npcID then ns.UI.MainWindow:OpenRare(npcID) end
        end,
    })

    local empty = listHost:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
    empty:SetPoint("CENTER", listHost, "CENTER", 0, 0)
    empty:SetWidth(460)
    empty:SetJustifyH("CENTER")
    empty:SetSpacing(3)
    empty:SetTextColor(0.6, 0.6, 0.6)
    panel.empty = empty

    function panel:Refresh()
        local known, unknown, seenIDs = {}, {}, {}
        wipe(self.recordsByKey)

        for npcID, sighting in pairs(ns.Collection.RareState:GetSightings()) do
            local record = ns.Data.RareCatalog:Get(npcID)
            if record then
                known[#known + 1] = { record = record, sighting = sighting }
                seenIDs[npcID] = true
            end
        end

        -- Preserve useful encounters recorded before the full catalogue was
        -- installed, and keep genuinely unknown family members as research.
        for npcID, sighting in pairs(ns.Collection.SightingTracker:GetSightings()) do
            local record = ns.Data.RareCatalog:Get(npcID)
            if record and not seenIDs[npcID] then
                known[#known + 1] = { record = record, sighting = sighting }
                seenIDs[npcID] = true
            elseif not record then
                unknown[#unknown + 1] = { npcID = npcID, sighting = sighting }
            end
        end

        if #known == 0 and #unknown == 0 then
            empty:SetText(ns.L["SIGHTINGS_EMPTY_USEFUL"])
            empty:Show()
            self.list.container:Hide()
            return
        end
        empty:Hide()
        self.list.container:Show()
        table.sort(known, function(a, b)
            return (a.sighting.seenAt or 0) > (b.sighting.seenAt or 0)
        end)
        table.sort(unknown, function(a, b) return a.npcID < b.npcID end)

        local elements = {}
        if #known > 0 then
            elements[#elements + 1] = { kind = "header",
                name = ns.L["SIGHTINGS_KNOWN_HEADER"], counterText = tostring(#known) }
            for _, entry in ipairs(known) do
                local record, sighting = entry.record, entry.sighting
                local outcomeText, outcomeColor, completed =
                    OutcomePresentation(record.npcID)
                local key = "npc:" .. record.npcID
                local place = MapName(sighting.mapID or record.mapID)
                if sighting.x and sighting.y then
                    place = place .. " " .. ns.L["DETAIL_COORDS"]:format(
                        sighting.x * 100, sighting.y * 100)
                end
                self.recordsByKey[key] = record.npcID
                elements[#elements + 1] = {
                    name = record.name,
                    subtitle = ("%s · %s"):format(place,
                        sighting.seenAt and date("%d/%m %H:%M", sighting.seenAt) or "?"),
                    portraitDisplayID = record.displayIDs and record.displayIDs[1],
                    icon = "Interface\\Icons\\Ability_Hunter_BeastCall",
                    desaturated = not completed,
                    selectionID = key,
                    statusText = outcomeText or ns.L["SIGHTINGS_OPEN_DOSSIER"],
                    statusColor = outcomeColor,
                    catalogText = tostring(record.npcID),
                }
            end
        end
        if #unknown > 0 then
            elements[#elements + 1] = { kind = "header",
                name = ns.L["SIGHTINGS_RESEARCH_HEADER"], counterText = tostring(#unknown) }
            for _, entry in ipairs(unknown) do
                elements[#elements + 1] = {
                    name = entry.sighting.name or "?",
                    subtitle = tostring(entry.sighting.family or "?") .. " · NPC " .. entry.npcID,
                    statusText = ns.L["SIGHTINGS_RESEARCH_STATUS"],
                    statusColor = UNKNOWN_COLOR,
                }
            end
        end
        self.list:SetElements(elements)
    end

    ns.Events:Subscribe("RARE_SIGHTING_CHANGED", panel, function() panel:Refresh() end)
    ns.Events:Subscribe("RARE_COLLECTION_CHANGED", panel, function() panel:Refresh() end)
    ns.Events:Subscribe("SIGHTING_ADDED", panel, function() panel:Refresh() end)
    ns.Events:Subscribe("CONFIG_CHANGED", panel, function(_, key)
        if key == "alertScope" then panel:RefreshAlertScope() end
    end)
    ns.Events:Subscribe("DATABASE_RESET", panel,
        function() panel:RefreshAlertScope() end)
    panel:RefreshAlertScope()
    panel:Refresh()
    return panel
end
