--Automatically add Dreamseed locations to Super Track
--Waypoints Priority: 1.Growing (haven't contributed)  2.Chest Available  3.Growing (contributed)


local _, addon = ...
local API = addon.API;

local WIDGET_UPDATE_INTERVAL = 2;
local WAYPOINT_MIN_DISTANCE = 10;   --Don't add waypoint if it's closeby
local WAYPOINT_PRIOTIRY_DISTANCE = 180;  --Prioritize location that is within x yd away from player --253 yd is where Dreamseed Chest shown on WorldMap
local VIGID_BOUNTY = 5971;
local MAPID_EMRALD_DREAM = 2200;

local DreamseedUtil = API.DreamseedUtil;    --Defined in Dreamseed.lua
local GetCreatureIDFromGUID = API.GetCreatureIDFromGUID;
local GetPlayerMapCoord = API.GetPlayerMapCoord;

local SuperTrackFrame;

local C_VignetteInfo = C_VignetteInfo;
local ClearUserWaypoint = C_Map.ClearUserWaypoint;
local tinsert = table.insert;
local tsort = table.sort;

local EL;
local MODULE_ENABLED = false;
local DREAMSEED_FLAGS = {};    --key: creatureID
local CHEST_VIGNETTE_X_CREATURE = {};
local NAME_DREAMSEED_CHEST = nil; --Localized later by API
local FOCUSED_CREATURE;     --Plant shown on the Arrow
local PRIORITIZE_CHEST = false;   --if false, don't add new waypoints so player can go back and collect rewards


--Flags
--0: not spawned or not growing
--1: growing, contributed
--2: finished growing, has rewards (chest)
--3: growing, haven't contributed

local FLAG_ICON = {
    [0] = "Dreamseed-Active",
    [1] = "Dreamseed-Active-Visited",
    [2] = "Dreamseed-Chest",
    [3] = "Dreamseed-Active-New",
};

local function SetDreamseedFlag(creatureID, flag)
    if DREAMSEED_FLAGS[creatureID] then
        if DREAMSEED_FLAGS[creatureID] ~= flag then
            DREAMSEED_FLAGS[creatureID] = flag;
            return true
        end
    end
end

local function GetPlantPosition(creatureID)
    local pos = DreamseedUtil:GetBackupLocation(creatureID);
    return pos[1], pos[2]
end

function DreamseedUtil:SetNavigatorPrioritizingReward(state)
    PRIORITIZE_CHEST = state;
end

function DreamseedUtil:IsNavigatorPrioritizingReward()
    return PRIORITIZE_CHEST
end


local function SortFunc_Generic(loc1, loc2)
    --locationData: creatureID, x, y, flag, remainingTime, distance

    --Prioritize nearyby spawned chest
    if loc1[4] == 2 and loc1[6] < WAYPOINT_PRIOTIRY_DISTANCE then
        return true
    elseif loc2[4] == 2 and loc2[6] < WAYPOINT_PRIOTIRY_DISTANCE then
        return false
    end

    --If there are two uncontributed plants, prioritize the one whose time is running out
    if loc1[4] == 3 and loc2[4] == 3 then
        if loc1[5] + 60 < loc2[5] then
            return true
        elseif loc2[5] + 60 < loc1[5] then
            return false
        end
    end

    if loc1[4] ~= loc2[4] then
        return loc1[4] > loc2[4]
    elseif loc1[6] ~= loc2[6] then
        return loc1[6] < loc2[6]
    end

    return false
end

local function SortFunc_RewardFirst(loc1, loc2)
    --Prioritize nearyby spawned chest
    if loc1[4] == 2 then
        if loc2[4] == 2 then
            return loc1[6] < loc2[6]
        else
            return true
        end
    elseif loc2[4] == 2 then
        return false
    end

    if loc1[4] == 1 then
        if loc2[4] == 1 then
            --prioritize time
            return loc1[5] < loc2[5]
        else
            return true
        end
    elseif loc2[4] == 1 then
        return false
    end

    if loc1[6] ~= loc2[6] then
        return loc1[6] < loc2[6]
    end

    return false
end


local function UpdateWaypoints()
    if not (SuperTrackFrame and SuperTrackFrame:CanReceiveDataFromNavigator()) then return end;

    local playerX, playerY = GetPlayerMapCoord(MAPID_EMRALD_DREAM);
    if not (playerX and playerY) then return end;

    local vignetteGUIDs = C_VignetteInfo.GetVignettes();
    local info;
    local uiMapID = MAPID_EMRALD_DREAM;
    local creatureID;
    local x, y;
    local remainingTime, fullTime;
    local isActive;
    local hasReward, distance;
    local flag;
    local locations;
    local processedCreatures = {};

    for i, vignetteGUID in ipairs(vignetteGUIDs) do
        info = C_VignetteInfo.GetVignetteInfo(vignetteGUID);
        if info then
            if info.vignetteID == VIGID_BOUNTY then
                --Soil
                creatureID = GetCreatureIDFromGUID(info.objectGUID);
            elseif CHEST_VIGNETTE_X_CREATURE[info.vignetteID] then
                --Dreamseed Chest
                if not NAME_DREAMSEED_CHEST then
                    NAME_DREAMSEED_CHEST = info.name or "Dreamseed Chest";
                    NAME_DREAMSEED_CHEST = "|cff19ff19"..(NAME_DREAMSEED_CHEST or "Dreamseed Chest").."|r";
                end

                flag = 2;
                creatureID = CHEST_VIGNETTE_X_CREATURE[info.vignetteID];
                if not processedCreatures[creatureID] then
                    processedCreatures[creatureID] = true;
                    SetDreamseedFlag(creatureID, flag);

                    local vignettePosition, vignetteFacing = C_VignetteInfo.GetVignettePosition(info.vignetteGUID, uiMapID);
                    x, y = vignettePosition:GetXY();
                    distance = DreamseedUtil:GetPlayerDistanceToTarget(playerX, playerY, x, y);

                    if distance >= WAYPOINT_MIN_DISTANCE then
                        if not locations then
                            locations = {};
                        end
                        tinsert(locations, {creatureID, x, y, flag, 0, distance});
                    end

                    DreamseedUtil:SetPlantContributedByCreatureID(creatureID, true);
                end
            end
        end
    end

    for creatureID in pairs(DREAMSEED_FLAGS) do
        if not processedCreatures[creatureID] then
            processedCreatures[creatureID] = true;
            remainingTime, fullTime = DreamseedUtil:GetGrowthTimesByCreatureID(creatureID);
            isActive = remainingTime and remainingTime > 0;

            if DreamseedUtil:HasAnyRewardByCreatureID(creatureID) then
                if isActive then
                    flag = 1;
                else
                    flag = 2;
                end
            else
                if isActive then
                    if remainingTime > 5 then
                        --We hide the uncontributed plant that is about to despawn
                        flag = 3;
                    else
                        flag = 0;
                    end
                else
                    flag = 0;
                end
            end

            SetDreamseedFlag(creatureID, flag)
            hasReward = flag == 1 or flag == 2;
            if isActive then
                x, y = GetPlantPosition(creatureID);
                distance = DreamseedUtil:GetPlayerDistanceToTarget(playerX, playerY, x, y);
                if distance >= WAYPOINT_MIN_DISTANCE then
                    if not locations then
                        locations = {};
                    end
                    tinsert(locations, {creatureID, x, y, flag, remainingTime, distance});
                end
            elseif hasReward then
                if not locations then
                    locations = {};
                end
                x, y = GetPlantPosition(creatureID);
                distance = DreamseedUtil:GetPlayerDistanceToTarget(playerX, playerY, x, y);
                if distance >= WAYPOINT_MIN_DISTANCE then
                    if not locations then
                        locations = {};
                    end
                    tinsert(locations, {creatureID, x, y, flag, 0, distance});
                end
            end
        end
    end

    if locations then
        if PRIORITIZE_CHEST then
            tsort(locations, SortFunc_RewardFirst);
        else
            tsort(locations, SortFunc_Generic);
        end
    end

    local bestCreatureID = locations and locations[1] and locations[1][1];

    if bestCreatureID ~= FOCUSED_CREATURE or true then
        FOCUSED_CREATURE = bestCreatureID;
        if bestCreatureID then
            local data = locations[1];
            flag = data[4];
            creatureID = data[1];
            local plantName;
            if flag == 2 then
                plantName = NAME_DREAMSEED_CHEST;
            else
                plantName = DreamseedUtil:GetPlantNameByCreatureID(data[1]);
                if flag == 3 then   --haven't contributed
                    --plantName = plantName.."|TInterface/AddOns/Plumber/Art/MapPin/RedDot:8:8:4:4|t";
                elseif flag == 1 then   --has reward but still growing
                    plantName = "|cffcccccc"..plantName.."|r";
                end
            end

            if flag == 0 then
                ClearUserWaypoint();
                return
            end
            local hasTimer = flag == 3 or flag == 1;
            SuperTrackFrame:SetTimerTarget(plantName, uiMapID, data[2], data[3], FLAG_ICON[flag], hasTimer, data[5]);
        else
            ClearUserWaypoint();
        end
    end
end

local function EL_UpdateNow_OnUpdate(self, elapsed)
    self.t = self.t + elapsed;
    if self.t > WIDGET_UPDATE_INTERVAL then
        self.t = 0;
        self:SetScript("OnUpdate", nil);
        if MODULE_ENABLED then
            self:RegisterEvent("VIGNETTES_UPDATED");
            self:RegisterEvent("UPDATE_UI_WIDGET");
        end
    end
end

local function EL_UpdateAfter_OnUpdate(self, elapsed)
    self.t = self.t + elapsed;
    if self.t > 1 then
        self.t = 0;
        self:SetScript("OnUpdate", nil);
        if MODULE_ENABLED then
            UpdateWaypoints();
            self:RegisterEvent("VIGNETTES_UPDATED");
            self:RegisterEvent("UPDATE_UI_WIDGET");
        end
    end
end

local function EL_OnEvent(self, event)
    if event == "VIGNETTES_UPDATED" then
        self.t = 0;
        self:SetScript("OnUpdate", EL_UpdateAfter_OnUpdate);
        self:UnregisterEvent(event);
    elseif event == "UPDATE_UI_WIDGET" then
        self.t = 0;
        UpdateWaypoints();
        self:SetScript("OnUpdate", EL_UpdateNow_OnUpdate);
        self:UnregisterEvent(event);
    end
end

local function EnableEventListener(state)
    if EL then
        MODULE_ENABLED = state;
        if state then
            for creatureID in pairs(DREAMSEED_FLAGS) do
                DREAMSEED_FLAGS[creatureID] = 0;
            end
            EL:RegisterEvent("UPDATE_UI_WIDGET");
            EL:RegisterEvent("VIGNETTES_UPDATED");
            if not SuperTrackFrame then
                SuperTrackFrame = addon.GetSuperTrackFrame();
            end
            SuperTrackFrame:TryEnableByModule();
        else
            EL:UnregisterEvent("UPDATE_UI_WIDGET");
            EL:UnregisterEvent("VIGNETTES_UPDATED");
            EL:SetScript("OnUpdate", nil);
            EL.t = 0;
            FOCUSED_CREATURE = nil;
            if SuperTrackFrame then
                SuperTrackFrame:EnableSuperTracking(false);
            end
        end
    end
end


local ZoneTriggerModule;

local function EnableModule(state)
    if state then
        if not EL then
            EL = CreateFrame("Frame");
            EL:SetScript("OnEvent", EL_OnEvent);
            DREAMSEED_FLAGS = DreamseedUtil:GetPlantCreatureIDs();
            CHEST_VIGNETTE_X_CREATURE = DreamseedUtil:GetChestOwnerCreatureIDs();
        end

        if not ZoneTriggerModule then
            local module = API.CreateZoneTriggeredModule("navigator-dreamseed");
            ZoneTriggerModule = module;

            module:SetValidZones(MAPID_EMRALD_DREAM);

            local function OnEnterZoneCallback()
                EnableEventListener(true);
            end

            local function OnLeaveZoneCallback()
                EnableEventListener(false);
            end

            module:SetEnterZoneCallback(OnEnterZoneCallback);
            module:SetLeaveZoneCallback(OnLeaveZoneCallback);
        end

        ZoneTriggerModule:SetEnabled(true);
        ZoneTriggerModule:Update();
    else
        if ZoneTriggerModule then
            ZoneTriggerModule:SetEnabled(false);
        end
        EnableEventListener(false);
    end
end

do
    local moduleData = {
        name = addon.L["ModuleName Navigator_Dreamseed"],
        dbKey = "Navigator_Dreamseed",   --WorldMapPinSeedPlanting
        description = addon.L["ModuleDescription Navigator_Dreamseed"],
        toggleFunc = EnableModule,
        moduleAddedTime = 1702258000,
        categoryID = 10020001,
        uiOrder = 4,
    };

    addon.ControlCenter:AddModule(moduleData);
end