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


local EL = CreateFrame("Frame");
EL:RegisterEvent("PLAYER_ENTERING_WORLD");


function EL:OnEvent_ADDON_LOADED(event, addOnName)
    if addOnName == "Blizzard_Collections" then
        self:UnregisterEvent(event);
        self:Modify();
    end
end

EL:SetScript("OnEvent", function(self, event, ...)
    self:UnregisterEvent(event);
    self:RegisterEvent("ADDON_LOADED");
    self:SetScript("OnEvent", EL.OnEvent_ADDON_LOADED);
end);


local Loader = CreateFrame("Frame", nil, UIParent);
Loader.delayBetweenLoading = 0.1;
do
    Loader.queue = {};
    Loader.queuedModels = {};

    local tremove = table.remove;

    function Loader:LoadNextModel()
        self.t = 0;
        self:SetScript("OnUpdate", self.OnUpdate);
    end

    function Loader:OnUpdate(elapsed)
        self.t = self.t + elapsed;
        if self.t > self.delayBetweenLoading then
            self.t = 0;
            self:SetScript("OnUpdate", nil);
            local widgetInfo = tremove(self.queue, 1);
            if widgetInfo then
                local widget = widgetInfo.widget;
                self.queuedModels[widget] = nil;
                if widget:IsVisible() then
                    widget.RealSetUnit(widget, widgetInfo.unit, widgetInfo.blend, widgetInfo.useNativeForm);
                else
                    self:SetScript("OnUpdate", self.OnUpdate);
                    WardrobeCollectionFrame.ItemsCollectionFrame:UpdateItems();
                end
            end
        end
    end

    function Loader:QueueModelWidget(widget, unit, blend, useNativeForm)
        local index = self.queuedModels[widget];

        if not index then
            index = #self.queue + 1;
            self.queuedModels[widget] = index;
        end

        widget:ClearModel();

        self.queue[index] = {
            widget = widget,
            unit = unit,
            blend = blend,
            useNativeForm = useNativeForm,
        };

        self:LoadNextModel();
    end

    function Loader:LoadWidgetVisualInfo(model)
        local visualInfo = model.visualInfo;
        if not visualInfo then return end;

        local f = WardrobeCollectionFrame.ItemsCollectionFrame;
        local canDisplayVisuals = f.transmogLocation:IsIllusion() or visualInfo.canDisplayOnPlayer;
        if not f.activeCategory then return end;
        local _, isWeapon = C_TransmogCollection.GetCategoryInfo(f.activeCategory);
		local isArmor = not isWeapon;

        if ( not canDisplayVisuals ) then
            if ( isArmor ) then
                model:UndressSlot(f.transmogLocation:GetSlotID());
            end
        elseif ( isArmor ) then
            local sourceID = f:GetAnAppearanceSourceFromVisual(visualInfo.visualID, nil);
            model:TryOn(sourceID);
        end
    end
end


local WardrobeItemsModelMixin = {};
do
    local Model_ApplyUICamera = Model_ApplyUICamera;

    function WardrobeItemsModelMixin:OnModelLoaded()
        if ( self.cameraID ) then
            Model_ApplyUICamera(self, self.cameraID);
        end
        self.desaturated = false;

        if Loader.isWeapon then
            return
        end

        Loader:LoadNextModel();
        C_Timer.After(0, function()
            Loader:LoadWidgetVisualInfo(self);
        end);

        --print(math.random(100), "ModelLoaded")
    end

    function WardrobeItemsModelMixin:SetUnit(unit, blend, useNativeForm)
        Loader:QueueModelWidget(self, unit, blend, useNativeForm);
    end
end


function EL:Modify()
    local models = WardrobeCollectionFrame.ItemsCollectionFrame.Models;
    local Mixin = Mixin;

    local NUM_ROWS = 2; --3
	local NUM_COLS = 4; --6

    NUM_ROWS = math.min(NUM_ROWS, 3);
    NUM_COLS = math.min(NUM_COLS, 6);
	local PAGE_SIZE = NUM_ROWS * NUM_COLS;

    local gapH, gapV = 16, 24;
    local modelWidth, modelHeight = 78, 104;

    local f = WardrobeCollectionFrame.ItemsCollectionFrame;
    f.NUM_ROWS = NUM_ROWS;
    f.NUM_COLS = NUM_COLS;
    f.PAGE_SIZE = PAGE_SIZE;

    local fromOffsetY = -92;
    local fromOffsetX = -math.floor(0.5 * (NUM_COLS * (modelWidth + gapH) - gapH));

    local row = 0;
    local col = 0;

    for i, model in ipairs(models) do
        model.RealSetUnit = model.SetUnit;
        Mixin(model, WardrobeItemsModelMixin);
        model:SetScript("OnModelLoaded", WardrobeItemsModelMixin.OnModelLoaded);

        if i > PAGE_SIZE then
            model:Hide();
            model:ClearModel();
        else
            col = col + 1;
            if col > NUM_COLS then
                col = 1;
                row = row + 1;
            end
            model:ClearAllPoints();
            model:SetPoint("TOPLEFT", f, "TOP", fromOffsetX + (col - 1) * (modelWidth + gapH), fromOffsetY - row * (modelHeight + gapV));
        end
    end


    local processed = false;
    WardrobeCollectionFrame:HookScript("OnKeyDown", function(self, key)
        if (not hooked) and (key == "ESCAPE" and not InCombatLockdown()) then
            processed = true;
            self:SetPropagateKeyboardInput(true);
        end
    end)

    if not InCombatLockdown() then
        WardrobeCollectionFrame:SetPropagateKeyboardInput(true);
    end

    EL.lastPages = {};

    hooksecurefunc(f, "SetActiveCategory", function(_, category)
        EL.activeCategory = category;
        local _, isWeapon = category and C_TransmogCollection.GetCategoryInfo(category);
        if isWeapon or (f.transmogLocation and f.transmogLocation:IsIllusion()) then
            Loader.isWeapon = true;
        else
            Loader.isWeapon = false;
        end
    end);

    --[[

    local function ResetPage(self)
        local activeCategory = self.activeCategory;
        local currentPage = f.PagingFrame:GetCurrentPage();
        local oldCategory = EL.activeCategory;
        print("oldCategory", oldCategory)
        if oldCategory then
            print("old page", currentPage)
            EL.lastPages[oldCategory] = currentPage;
        end

        local page = EL.lastPages[activeCategory] or 1;

        local selectedVisualID = NO_TRANSMOG_VISUAL_ID;
        if ( C_TransmogCollection.IsSearchInProgress(self:GetParent():GetSearchType()) ) then
            self.resetPageOnSearchUpdated = true;
        else
            if ( self.jumpToVisualID ) then
                selectedVisualID = self.jumpToVisualID;
                self.jumpToVisualID = nil;
            elseif ( self.jumpToLatestAppearanceID and not C_Transmog.IsAtTransmogNPC() ) then
                selectedVisualID = self.jumpToLatestAppearanceID;
                self.jumpToLatestAppearanceID = nil;
            end
        end
        if ( selectedVisualID and selectedVisualID ~= NO_TRANSMOG_VISUAL_ID ) then
            local visualsList = self:GetFilteredVisualsList();
            for i = 1, #visualsList do
                if ( visualsList[i].visualID == selectedVisualID ) then
                    page = CollectionWardrobeUtil.GetPage(i, self.PAGE_SIZE);
                    break;
                end
            end
        end
        self.PagingFrame:SetCurrentPage(page);
        self:UpdateItems();
    end
    f.ResetPage = ResetPage;
    --]]

    --[[
    local callers = {"SetActiveCategory", "OnSearchUpdate", "GoToSourceID", "UpdateItems"};
    for _, caller in ipairs(callers) do
        hooksecurefunc(f, caller, function()
            print(caller)
        end);
    end
    --]]
end