local addonName, addon = ...

local UI = addon.UI

local MONTHS = {
    "JANUARY",
    "FEBRUARY",
    "MARCH",
    "APRIL",
    "MAY",
    "JUNE",
    "JULY",
    "AUGUST",
    "SEPTEMBER",
    "OCTOBER",
    "NOVEMBER",
    "DECEMBER",
}

local WEEKDAYS = {
    "MO",
    "TU",
    "WE",
    "TH",
    "FR",
    "SA",
    "SU",
}

local function CharacterDisplay(
    character
)

    if not character then
        return "UNKNOWN"
    end

    return character.name
        or character.key
        or "UNKNOWN"
end

local function GetDaysInMonth(
    year,
    month
)

    local nextMonth =
        month + 1

    local nextYear =
        year

    if nextMonth > 12 then

        nextMonth = 1
        nextYear = nextYear + 1

    end

    local timestamp =
        time({
            year = nextYear,
            month = nextMonth,
            day = 1,
            hour = 12,
        })

    return tonumber(
        date(
            "%d",
            timestamp - 86400
        )
    )
end

local function GetFirstWeekday(
    year,
    month
)

    local timestamp =
        time({
            year = year,
            month = month,
            day = 1,
            hour = 12,
        })

    local weekday =
        tonumber(
            date(
                "%w",
                timestamp
            )
        )

    if weekday == 0 then
        return 7
    end

    return weekday
end

local function GetMonthEndDate(
    year,
    month
)

    return {
        year = year,
        month = month,
        day =
            GetDaysInMonth(
                year,
                month
            ),
    }
end

------------------------------------------------------------
-- RESET FILTERS
------------------------------------------------------------

function UI:ResetAllFilters()

    self.CategoryFilter =
        "ALL"

    self.FilterCharacterKey =
        "ALL"

    self.FilterSpecID =
        "ALL"

    self.FilterProfessionID =
        "ALL"

    self.FilterInstanceID =
        "ALL"

    self.FilterRaidExpansion =
        "ALL"

    if self.CategoryFilterDropDown then

        UIDropDownMenu_SetText(
            self.CategoryFilterDropDown,
            "ALL"
        )

    end

    if self.RefreshFilterSelectors then
        self:RefreshFilterSelectors()
    end

end

------------------------------------------------------------
-- INITIALIZE
------------------------------------------------------------

function UI:InitializeCalendar()

    local sidebar =
        self.Sidebar

    --------------------------------------------------------
    -- CALENDAR
    --------------------------------------------------------

    local calendarPanel =
        CreateFrame(
            "Frame",
            nil,
            sidebar
        )

    self.CalendarPanel =
        calendarPanel

    calendarPanel:SetPoint(
        "TOPLEFT",
        sidebar,
        "TOPLEFT",
        10,
        -8
    )

    calendarPanel:SetPoint(
        "TOPRIGHT",
        sidebar,
        "TOPRIGHT",
        -10,
        -8
    )

    calendarPanel:SetHeight(245)

    local calendarTitle =
        calendarPanel:CreateFontString(
            nil,
            "OVERLAY"
        )

    calendarTitle:SetFontObject(
        GameFontNormalLarge
    )

    calendarTitle:SetPoint(
        "TOP",
        calendarPanel,
        "TOP",
        0,
        -4
    )

    calendarTitle:SetText(UI:LT("CALENDAR"))

    calendarTitle:SetTextColor(
        unpack(self.COLORS.gold)
    )

    local previousButton =
        CreateFrame(
            "Button",
            nil,
            calendarPanel,
            "UIPanelButtonTemplate"
        )

    previousButton:SetSize(30, 24)

    previousButton:SetPoint(
        "TOPLEFT",
        calendarPanel,
        "TOPLEFT",
        0,
        -32
    )

    previousButton:SetText("<")

    local nextButton =
        CreateFrame(
            "Button",
            nil,
            calendarPanel,
            "UIPanelButtonTemplate"
        )

    nextButton:SetSize(30, 24)

    nextButton:SetPoint(
        "TOPRIGHT",
        calendarPanel,
        "TOPRIGHT",
        0,
        -32
    )

    nextButton:SetText(">")

    local monthTitle =
        calendarPanel:CreateFontString(
            nil,
            "OVERLAY"
        )

    self.CalendarMonthTitle =
        monthTitle

    monthTitle:SetFontObject(
        GameFontNormal
    )

    monthTitle:SetPoint(
        "TOP",
        calendarPanel,
        "TOP",
        0,
        -36
    )

    local todayButton =
        CreateFrame(
            "Button",
            nil,
            calendarPanel,
            "UIPanelButtonTemplate"
        )

    todayButton:SetSize(88, 24)

    todayButton:SetPoint(
        "TOP",
        calendarPanel,
        "TOP",
        0,
        -63
    )

    todayButton:SetText(UI:LT("TODAY"))

    local calendarGrid =
        CreateFrame(
            "Frame",
            nil,
            calendarPanel
        )

    self.CalendarGrid =
        calendarGrid

    calendarGrid:SetPoint(
        "TOP",
        calendarPanel,
        "TOP",
        0,
        -92
    )

    calendarGrid:SetSize(
        280,
        145
    )

    self.CalendarYear =
        tonumber(
            date("%Y")
        )

    self.CalendarMonthNumber =
        tonumber(
            date("%m")
        )

    --------------------------------------------------------
    -- FILTERS
    --------------------------------------------------------

    local filtersPanel =
        CreateFrame(
            "Frame",
            nil,
            self.TaskPanel,
            "BackdropTemplate"
        )

    self.FiltersPanel =
        filtersPanel

    filtersPanel:SetPoint(
        "TOPLEFT",
        self.TaskPanel,
        "TOPLEFT",
        140,
        -7
    )

    filtersPanel:SetPoint(
        "TOPRIGHT",
        self.TaskPanel,
        "TOPRIGHT",
        -12,
        -7
    )

    filtersPanel:SetHeight(
        38
    )

    filtersPanel:SetBackdrop({
        bgFile =
            "Interface\\Buttons\\WHITE8X8",

        edgeFile =
            "Interface\\Tooltips\\UI-Tooltip-Border",

        edgeSize = 8,
    })

    filtersPanel:SetBackdropColor(
        0.025,
        0.025,
        0.035,
        0.55
    )

    filtersPanel:SetBackdropBorderColor(
        unpack(self.COLORS.border)
    )

    local filtersTitle =
        filtersPanel:CreateFontString(
            nil,
            "OVERLAY"
        )

    filtersTitle:SetFontObject(
        GameFontNormal
    )

    filtersTitle:SetPoint(
        "LEFT",
        filtersPanel,
        "LEFT",
        8,
        0
    )

    filtersTitle:SetText(UI:LT("FILTERS"))

    filtersTitle:SetTextColor(
        unpack(self.COLORS.gold)
    )

    local filterCategoryLabel =
        filtersPanel:CreateFontString(
            nil,
            "OVERLAY"
        )

    filterCategoryLabel:SetFontObject(
        GameFontNormalSmall
    )

    filterCategoryLabel:SetPoint(
        "TOPLEFT",
        filtersPanel,
        "TOPLEFT",
        10,
        -27
    )

    filterCategoryLabel:SetText(UI:LT("CATEGORY"))

    filterCategoryLabel:SetTextColor(
        unpack(self.COLORS.muted)
    )

    filterCategoryLabel:Hide()

    --------------------------------------------------------
    -- CATEGORY FILTER
    --------------------------------------------------------

    local categoryFilter =
        CreateFrame(
            "Frame",
            "WhatsNextCategoryFilterDropDown",
            filtersPanel,
            "UIDropDownMenuTemplate"
        )

    self.CategoryFilterDropDown =
        categoryFilter

    categoryFilter:SetPoint(
        "LEFT",
        filtersPanel,
        "LEFT",
        62,
        0
    )

    UIDropDownMenu_SetWidth(
        categoryFilter,
        145
    )

    UIDropDownMenu_SetText(
        categoryFilter,
        "ALL"
    )

    --------------------------------------------------------
    -- DETAIL FILTERS
    --------------------------------------------------------

    local detailFilter1 =
        CreateFrame(
            "Frame",
            "WhatsNextDetailFilterDropDown1",
            filtersPanel,
            "UIDropDownMenuTemplate"
        )

    local detailFilter2 =
        CreateFrame(
            "Frame",
            "WhatsNextDetailFilterDropDown2",
            filtersPanel,
            "UIDropDownMenuTemplate"
        )

    self.DetailFilterDropDown1 =
        detailFilter1

    self.DetailFilterDropDown2 =
        detailFilter2

    detailFilter1:SetPoint(
        "LEFT",
        filtersPanel,
        "LEFT",
        238,
        0
    )

    detailFilter2:SetPoint(
        "LEFT",
        filtersPanel,
        "LEFT",
        442,
        0
    )

    UIDropDownMenu_SetWidth(
        detailFilter1,
        170
    )

    UIDropDownMenu_SetWidth(
        detailFilter2,
        190
    )

    --------------------------------------------------------
    -- REFRESH FILTER SELECTORS
    --------------------------------------------------------

    function self:RefreshFilterSelectors()

        local category =
            self.CategoryFilter
            or "ALL"

        detailFilter1:Hide()
        detailFilter2:Hide()

        ----------------------------------------------------
        -- CHARACTER
        ----------------------------------------------------

        if category == "CHARACTER" then

            detailFilter1:Show()
            detailFilter2:Show()

            local characterText =
                self:T("ALL_CHARACTERS", "ALL CHARACTERS")

            if self.FilterCharacterKey ~=
                "ALL"
            then

                characterText =
                    CharacterDisplay(
                        addon.GameData:GetCharacter(
                            self.FilterCharacterKey
                        )
                    )

            end

            UIDropDownMenu_SetText(
                detailFilter1,
                characterText
            )

            UIDropDownMenu_Initialize(
                detailFilter1,
                function()

                    local allInfo =
                        UIDropDownMenu_CreateInfo()

                    allInfo.text =
                        self:T("ALL_CHARACTERS", "ALL CHARACTERS")

                    allInfo.func =
                        function()

                            self.FilterCharacterKey =
                                "ALL"

                            self.FilterSpecID =
                                "ALL"

                            self:RefreshFilterSelectors()
                            self:Refresh()

                        end

                    UIDropDownMenu_AddButton(
                        allInfo
                    )

                    for _, character in ipairs(
                        addon.GameData:GetCharacters()
                    ) do

                        local info =
                            UIDropDownMenu_CreateInfo()

                        info.text =
                            CharacterDisplay(
                                character
                            )

                        info.func =
                            function()

                                self.FilterCharacterKey =
                                    character.key

                                self.FilterSpecID =
                                    "ALL"

                                self:RefreshFilterSelectors()
                                self:Refresh()

                            end

                        UIDropDownMenu_AddButton(
                            info
                        )

                    end

                end
            )

            local specText =
                self:T("ALL_SPECS", "ALL SPECS")

            if self.FilterSpecID ~= "ALL"
                and self.FilterCharacterKey ~=
                    "ALL"
            then

                for _, spec in ipairs(
                    addon.GameData:GetSpecs(
                        self.FilterCharacterKey
                    )
                ) do

                    if tonumber(spec.id) ==
                        tonumber(
                            self.FilterSpecID
                        )
                    then

                        specText =
                            spec.name

                        break

                    end

                end

            end

            UIDropDownMenu_SetText(
                detailFilter2,
                specText
            )

            UIDropDownMenu_Initialize(
                detailFilter2,
                function()

                    local allInfo =
                        UIDropDownMenu_CreateInfo()

                    allInfo.text =
                        self:T("ALL_SPECS", "ALL SPECS")

                    allInfo.func =
                        function()

                            self.FilterSpecID =
                                "ALL"

                            self:RefreshFilterSelectors()
                            self:Refresh()

                        end

                    UIDropDownMenu_AddButton(
                        allInfo
                    )

                    if self.FilterCharacterKey ~=
                        "ALL"
                    then

                        for _, spec in ipairs(
                            addon.GameData:GetSpecs(
                                self.FilterCharacterKey
                            )
                        ) do

                            local info =
                                UIDropDownMenu_CreateInfo()

                            info.text =
                                spec.name

                            info.func =
                                function()

                                    self.FilterSpecID =
                                        spec.id

                                    self:RefreshFilterSelectors()
                                    self:Refresh()

                                end

                            UIDropDownMenu_AddButton(
                                info
                            )

                        end

                    end

                end
            )

        ----------------------------------------------------
        -- PROFESSION
        ----------------------------------------------------

        elseif category ==
            "PROFESSION"
        then

            detailFilter1:Show()
            detailFilter2:Show()

            local characterText =
                self:T("ALL_CHARACTERS", "ALL CHARACTERS")

            if self.FilterCharacterKey ~=
                "ALL"
            then

                characterText =
                    CharacterDisplay(
                        addon.GameData:GetCharacter(
                            self.FilterCharacterKey
                        )
                    )

            end

            UIDropDownMenu_SetText(
                detailFilter1,
                characterText
            )

            UIDropDownMenu_Initialize(
                detailFilter1,
                function()

                    local allInfo =
                        UIDropDownMenu_CreateInfo()

                    allInfo.text =
                        self:T("ALL_CHARACTERS", "ALL CHARACTERS")

                    allInfo.func =
                        function()

                            self.FilterCharacterKey =
                                "ALL"

                            self.FilterProfessionID =
                                "ALL"

                            self:RefreshFilterSelectors()
                            self:Refresh()

                        end

                    UIDropDownMenu_AddButton(
                        allInfo
                    )

                    for _, character in ipairs(
                        addon.GameData:GetCharacters()
                    ) do

                        local info =
                            UIDropDownMenu_CreateInfo()

                        info.text =
                            CharacterDisplay(
                                character
                            )

                        info.func =
                            function()

                                self.FilterCharacterKey =
                                    character.key

                                self.FilterProfessionID =
                                    "ALL"

                                self:RefreshFilterSelectors()
                                self:Refresh()

                            end

                        UIDropDownMenu_AddButton(
                            info
                        )

                    end

                end
            )

            local professionText =
                self:T("ALL_PROFESSIONS", "ALL PROFESSIONS")

            if self.FilterProfessionID ~=
                "ALL"
                and self.FilterCharacterKey ~=
                    "ALL"
            then

                for _, profession in ipairs(
                    addon.GameData:GetProfessions(
                        self.FilterCharacterKey
                    )
                ) do

                    if tonumber(
                        profession.id
                    ) == tonumber(
                        self.FilterProfessionID
                    )
                    then

                        professionText =
                            profession.name

                        break

                    end

                end

            end

            UIDropDownMenu_SetText(
                detailFilter2,
                professionText
            )

            UIDropDownMenu_Initialize(
                detailFilter2,
                function()

                    local allInfo =
                        UIDropDownMenu_CreateInfo()

                    allInfo.text =
                        self:T("ALL_PROFESSIONS", "ALL PROFESSIONS")

                    allInfo.func =
                        function()

                            self.FilterProfessionID =
                                "ALL"

                            self:RefreshFilterSelectors()
                            self:Refresh()

                        end

                    UIDropDownMenu_AddButton(
                        allInfo
                    )

                    if self.FilterCharacterKey ~=
                        "ALL"
                    then

                        for _, profession in ipairs(
                            addon.GameData:GetProfessions(
                                self.FilterCharacterKey
                            )
                        ) do

                            local info =
                                UIDropDownMenu_CreateInfo()

                            info.text =
                                profession.name

                            info.func =
                                function()

                                    self.FilterProfessionID =
                                        profession.id

                                    self:RefreshFilterSelectors()
                                    self:Refresh()

                                end

                            UIDropDownMenu_AddButton(
                                info
                            )

                        end

                    end

                end
            )

        ----------------------------------------------------
        -- DUNGEON = KEYS ONLY
        ----------------------------------------------------

        elseif category ==
            "DUNGEON"
        then

            detailFilter1:Show()

            local keyText =
                self:T("ALL_KEYS", "ALL KEYS")

            if self.FilterInstanceID ~=
                "ALL"
            then

                for _, keyData in ipairs(
                    addon.GameData:GetKeys()
                ) do

                    if tonumber(keyData.id) ==
                        tonumber(
                            self.FilterInstanceID
                        )
                    then

                        keyText =
                            keyData.name

                        break

                    end

                end

            end

            UIDropDownMenu_SetText(
                detailFilter1,
                keyText
            )

            UIDropDownMenu_Initialize(
                detailFilter1,
                function()

                    local allInfo =
                        UIDropDownMenu_CreateInfo()

                    allInfo.text =
                        self:T("ALL_KEYS", "ALL KEYS")

                    allInfo.func =
                        function()

                            self.FilterInstanceID =
                                "ALL"

                            self:RefreshFilterSelectors()
                            self:Refresh()

                        end

                    UIDropDownMenu_AddButton(
                        allInfo
                    )

                    for _, keyData in ipairs(
                        addon.GameData:GetKeys()
                    ) do

                        local info =
                            UIDropDownMenu_CreateInfo()

                        info.text =
                            keyData.name

                        info.func =
                            function()

                                self.FilterInstanceID =
                                    keyData.id

                                self:RefreshFilterSelectors()
                                self:Refresh()

                            end

                        UIDropDownMenu_AddButton(
                            info
                        )

                    end

                end
            )

        ----------------------------------------------------
        -- RAID: EXPANSION -> RAID
        ----------------------------------------------------

        elseif category ==
            "RAID"
        then

            detailFilter1:Show()
            detailFilter2:Show()

            local expansionText =
                self.FilterRaidExpansion

            if not expansionText
                or expansionText == "ALL"
            then
                expansionText =
                    self:T("ALL_EXPANSIONS", "ALL EXPANSIONS")
            end

            UIDropDownMenu_SetText(
                detailFilter1,
                expansionText
            )

            UIDropDownMenu_Initialize(
                detailFilter1,
                function()

                    local allInfo =
                        UIDropDownMenu_CreateInfo()

                    allInfo.text =
                        self:T("ALL_EXPANSIONS", "ALL EXPANSIONS")

                    allInfo.func =
                        function()

                            self.FilterRaidExpansion =
                                "ALL"

                            self.FilterInstanceID =
                                "ALL"

                            self:RefreshFilterSelectors()
                            self:Refresh()

                        end

                    UIDropDownMenu_AddButton(
                        allInfo
                    )

                    for _, expansion in ipairs(
                        addon.GameData:GetRaidExpansions()
                    ) do

                        local info =
                            UIDropDownMenu_CreateInfo()

                        info.text =
                            expansion.name

                        info.func =
                            function()

                                self.FilterRaidExpansion =
                                    expansion.name

                                self.FilterInstanceID =
                                    "ALL"

                                self:RefreshFilterSelectors()
                                self:Refresh()

                            end

                        UIDropDownMenu_AddButton(
                            info
                        )

                    end

                end
            )

            local raidText =
                self:T("ALL_RAIDS", "ALL RAIDS")

            local raids = {}

            if self.FilterRaidExpansion ==
                "ALL"
            then
                raids =
                    addon.GameData:GetRaids()
            else
                raids =
                    addon.GameData:GetRaidsForExpansion(
                        self.FilterRaidExpansion
                    )
            end

            if self.FilterInstanceID ~=
                "ALL"
            then

                for _, raid in ipairs(
                    raids
                ) do

                    if tonumber(raid.id) ==
                        tonumber(
                            self.FilterInstanceID
                        )
                    then

                        raidText =
                            raid.name

                        break

                    end

                end

            end

            UIDropDownMenu_SetText(
                detailFilter2,
                raidText
            )

            UIDropDownMenu_Initialize(
                detailFilter2,
                function()

                    local allInfo =
                        UIDropDownMenu_CreateInfo()

                    allInfo.text =
                        self:T("ALL_RAIDS", "ALL RAIDS")

                    allInfo.func =
                        function()

                            self.FilterInstanceID =
                                "ALL"

                            self:RefreshFilterSelectors()
                            self:Refresh()

                        end

                    UIDropDownMenu_AddButton(
                        allInfo
                    )

                    for _, raid in ipairs(
                        raids
                    ) do

                        local info =
                            UIDropDownMenu_CreateInfo()

                        info.text =
                            raid.name

                        info.func =
                            function()

                                self.FilterInstanceID =
                                    raid.id

                                self:RefreshFilterSelectors()
                                self:Refresh()

                            end

                        UIDropDownMenu_AddButton(
                            info
                        )

                    end

                end
            )

        end

    end

    --------------------------------------------------------
    -- CATEGORY MENU
    --------------------------------------------------------

    UIDropDownMenu_Initialize(
        categoryFilter,
        function()

            for _, option in ipairs(
                addon.DB:GetCategoryOptions()
            ) do

                local info =
                    UIDropDownMenu_CreateInfo()

                info.text =
                    option.text

                info.func =
                    function()

                        self.CategoryFilter =
                            option.value

                        self.FilterCharacterKey =
                            "ALL"

                        self.FilterSpecID =
                            "ALL"

                        self.FilterProfessionID =
                            "ALL"

                        self.FilterInstanceID =
                            "ALL"

                        self.FilterRaidExpansion =
                            "ALL"

                        UIDropDownMenu_SetText(
                            categoryFilter,
                            option.text
                        )

                        self:RefreshFilterSelectors()
                        self:Refresh()

                    end

                UIDropDownMenu_AddButton(
                    info
                )

            end

        end
    )

    --------------------------------------------------------
    -- MONTH BUTTONS
    --------------------------------------------------------

    previousButton:SetScript(
        "OnClick",
        function()

            self.CalendarMonthNumber =
                self.CalendarMonthNumber - 1

            if self.CalendarMonthNumber < 1 then

                self.CalendarMonthNumber =
                    12

                self.CalendarYear =
                    self.CalendarYear - 1

            end

            addon.DB:EnsureAllSeriesThroughDate(
                GetMonthEndDate(
                    self.CalendarYear,
                    self.CalendarMonthNumber
                )
            )

            self:RefreshCalendar()

        end
    )

    nextButton:SetScript(
        "OnClick",
        function()

            self.CalendarMonthNumber =
                self.CalendarMonthNumber + 1

            if self.CalendarMonthNumber > 12 then

                self.CalendarMonthNumber =
                    1

                self.CalendarYear =
                    self.CalendarYear + 1

            end

            addon.DB:EnsureAllSeriesThroughDate(
                GetMonthEndDate(
                    self.CalendarYear,
                    self.CalendarMonthNumber
                )
            )

            self:RefreshCalendar()

        end
    )

    todayButton:SetScript(
        "OnClick",
        function()

            local d =
                date("*t")

            self.SelectedDate = {
                year = d.year,
                month = d.month,
                day = d.day,
            }

            self.CalendarYear =
                d.year

            self.CalendarMonthNumber =
                d.month

            self.ViewMode =
                "day"

            self.NewTaskHasDate =
                true

            if self.DateButton then

                self.DateButton:SetText(
                    self:FormatDate(
                        self.SelectedDate
                    )
                )

            end

            self:Refresh()

        end
    )

    self:RefreshFilterSelectors()

end

------------------------------------------------------------
-- REFRESH CALENDAR
------------------------------------------------------------

function UI:RefreshCalendar()

    if not self.CalendarGrid then
        return
    end

    addon.DB:EnsureAllSeriesThroughDate(
        GetMonthEndDate(
            self.CalendarYear,
            self.CalendarMonthNumber
        )
    )

    self:ClearFrame(
        self.CalendarGrid
    )

    local grid =
        self.CalendarGrid

    local month =
        self.CalendarMonthNumber

    local year =
        self.CalendarYear

    self.CalendarMonthTitle:SetText(
        (self:T("MONTHS", MONTHS)[month] or MONTHS[month])
        .. " "
        .. year
    )

    local cellWidth = 40
    local cellHeight = 22

    --------------------------------------------------------
    -- WEEKDAYS
    --------------------------------------------------------

    for index, name in ipairs(
        self:T("WEEKDAYS", WEEKDAYS)
    ) do

        local text =
            grid:CreateFontString(
                nil,
                "OVERLAY"
            )

        text:SetFontObject(
            GameFontNormalSmall
        )

        text:SetPoint(
            "TOPLEFT",
            grid,
            "TOPLEFT",
            (index - 1) * cellWidth,
            0
        )

        text:SetSize(
            cellWidth,
            20
        )

        text:SetJustifyH(
            "CENTER"
        )

        text:SetText(name)

        text:SetTextColor(
            unpack(self.COLORS.muted)
        )

    end

    --------------------------------------------------------
    -- DAYS
    --------------------------------------------------------

    local first =
        GetFirstWeekday(
            year,
            month
        )

    local days =
        GetDaysInMonth(
            year,
            month
        )

    local today =
        date("*t")

    for day = 1, days do

        local pos =
            first + day - 2

        local row =
            math.floor(
                pos / 7
            )

        local column =
            pos % 7

        local button =
            CreateFrame(
                "Button",
                nil,
                grid,
                "BackdropTemplate"
            )

        button:SetSize(
            cellWidth,
            cellHeight
        )

        button:SetPoint(
            "TOPLEFT",
            grid,
            "TOPLEFT",
            column * cellWidth,
            -(row + 1) * cellHeight
        )

        button:SetBackdrop({
            bgFile =
                "Interface\\Buttons\\WHITE8X8",
        })

        local thisDate = {
            year = year,
            month = month,
            day = day,
        }

        if self:SameDate(
            self.SelectedDate,
            thisDate
        ) then

            button:SetBackdropColor(
                unpack(
                    self.COLORS.selected
                )
            )

        elseif
            today.year == year
            and today.month == month
            and today.day == day
        then

            button:SetBackdropColor(
                unpack(
                    self.COLORS.today
                )
            )

        else

            button:SetBackdropColor(
                0,
                0,
                0,
                0
            )

        end

        local text =
            button:CreateFontString(
                nil,
                "OVERLAY"
            )

        text:SetFontObject(
            GameFontNormal
        )

        text:SetAllPoints()
        text:SetJustifyH("CENTER")

        text:SetText(
            tostring(day)
        )

        text:SetTextColor(
            unpack(self.COLORS.text)
        )

        local tasks =
            addon.DB:GetTasksForDate(
                year,
                month,
                day
            )

        local visible = 0

        for _, task in ipairs(tasks) do

            if self:TaskPassesFilter(
                task
            ) then

                visible =
                    visible + 1

            end

        end

        if visible > 0 then

            local dot =
                button:CreateTexture(
                    nil,
                    "OVERLAY"
                )

            dot:SetSize(
                4,
                4
            )

            dot:SetPoint(
                "BOTTOM",
                button,
                "BOTTOM",
                0,
                2
            )

            dot:SetColorTexture(
                unpack(self.COLORS.gold)
            )

        end

        button:SetScript(
            "OnClick",
            function()

                self.SelectedDate = {
                    year = thisDate.year,
                    month = thisDate.month,
                    day = thisDate.day,
                }

                self.ViewMode =
                    "day"

                self.NewTaskHasDate =
                    true

                if self.DateButton then

                    self.DateButton:SetText(
                        self:FormatDate(
                            thisDate
                        )
                    )

                end

                self:Refresh()

            end
        )

    end

end
