ADS_MaintenanceLogDialog = {}
ADS_MaintenanceLogDialog.INSTANCE = nil

local ADS_MaintenanceLogDialog_mt = Class(ADS_MaintenanceLogDialog, MessageDialog)
local modDirectory = g_currentModDirectory

local function log_dbg(...)
    if ADS_Config and ADS_Config.DEBUG then
        local args = {...}
        for i = 1, #args do
            args[i] = tostring(args[i])
        end
        print(" " .. table.concat(args, " "))
    end
end

local function isLoggableRepairBreakdownId(breakdownId)
    return breakdownId ~= nil and breakdownId ~= "GENERAL_WEAR"
end

local function isLogEntryVisible(entry)
    if entry == nil then
        return false
    end

    local value = entry.isVisible
    if value == nil then
        return true
    end

    if type(value) == "string" then
        local v = string.lower(value)
        if v == "false" or v == "0" or v == "off" or v == "no" then
            return false
        end
        return true
    end

    return value ~= false
end

local function getResolvedBreakdownsCount(logEntries)
    if type(logEntries) ~= "table" then
        return 0
    end

    local total = 0
    local S = AdvancedDamageSystem.STATUS

    for _, entry in ipairs(logEntries) do
        if entry ~= nil and entry.isCompleted ~= false then
            local entryType = entry.type

            if entryType == S.REPAIR or entryType == S.OVERHAUL then
                local conditionData = entry.conditionData
                local selectedBreakdowns = conditionData ~= nil and conditionData.selectedBreakdowns or nil

                if type(selectedBreakdowns) == "table" then
                    for _, breakdownId in ipairs(selectedBreakdowns) do
                        if breakdownId ~= nil and breakdownId ~= "GENERAL_WEAR" then
                            total = total + 1
                        end
                    end
                end
            end
        end
    end

    return total
end

function ADS_MaintenanceLogDialog.register()
    local dialog = ADS_MaintenanceLogDialog.new()
    g_gui:loadGui(modDirectory .. "gui/ADS_MaintenanceLogDialog.xml", "ADS_MaintenanceLogDialog", dialog)
    ADS_MaintenanceLogDialog.INSTANCE = dialog
end

function ADS_MaintenanceLogDialog.new(target, customMt)
    local dialog = MessageDialog.new(target, customMt or ADS_MaintenanceLogDialog_mt)
    dialog.vehicle = nil
    dialog.logDataAll = nil
    dialog.selectedLogIndex = nil
    return dialog
end

function ADS_MaintenanceLogDialog:getSelectedLogEntry()
    if self.logData == nil or self.selectedLogIndex == nil then
        return nil
    end

    local entryIndex = #self.logData - self.selectedLogIndex + 1
    return self.logData[entryIndex]
end

function ADS_MaintenanceLogDialog:updateShowReportButtonState()
    if self.showReportButton == nil then
        return
    end

    local entry = self:getSelectedLogEntry()
    self.showReportButton.disabled = not (entry ~= nil and AdvancedDamageSystem.getIsLogEntryHasReport(entry))
end

function ADS_MaintenanceLogDialog:rebuildVisibleLogData()
    self.logData = {}
    if self.logDataAll == nil then
        return
    end

    for _, entry in ipairs(self.logDataAll) do
        if isLogEntryVisible(entry) then
            table.insert(self.logData, entry)
        end
    end
end

function ADS_MaintenanceLogDialog.show(vehicle)
    if ADS_MaintenanceLogDialog.INSTANCE == nil then ADS_MaintenanceLogDialog.register() end
    if vehicle == nil or vehicle.spec_AdvancedDamageSystem == nil then return end
    
    local dialog = ADS_MaintenanceLogDialog.INSTANCE
    dialog.vehicle = vehicle
    
    dialog.logDataAll = vehicle.spec_AdvancedDamageSystem.maintenanceLog or {}
    dialog:rebuildVisibleLogData()
    dialog.selectedLogIndex = #dialog.logData > 0 and 1 or nil
    
    dialog:updateScreen()
    g_gui:showDialog("ADS_MaintenanceLogDialog")
end

function ADS_MaintenanceLogDialog:updateScreen()
    if self.vehicle == nil then return end
    log_dbg("Updating log Screen...")

    local spec = self.vehicle.spec_AdvancedDamageSystem
    self.logDataAll = spec.maintenanceLog or {}
    self:rebuildVisibleLogData()

    local balanceText = g_i18n:formatMoney(g_currentMission:getMoney(), 0, true, true)
    self.balanceElement:setText(balanceText)
    ADS_Utils.updateMoneyBoxLayout(
        self.balanceTitleElement,
        self.balanceElement,
        self.moneyBox,
        self.moneyBoxBg,
        g_i18n:getText("ui_balance"),
        balanceText
    )
    self.vehicleNameValue:setText(g_i18n:getText('ads_log_title') .. " " .. self.vehicle:getFullName())

    local totalCost = 0
    local totalBreakdowns = getResolvedBreakdownsCount(self.logDataAll)
    local purchaseDate = {}
    local purchaseHours = 0

    for _, entry in pairs(self.logDataAll) do
        totalCost = totalCost + (entry.price or 0)
        if entry.id == 1 then
            purchaseDate = entry.date or {}
            purchaseHours = entry.conditionData and entry.conditionData.operatingHours or 0
        end
    end

    self.totalCostValue:setText(g_i18n:formatMoney(totalCost, 0, true, true))

    local currentYear = g_currentMission.environment.currentYear
    local currentMonth = g_currentMission.environment.currentPeriod
    
    local pMonth = (purchaseDate and purchaseDate.month) or currentMonth
    local pYear = (purchaseDate and purchaseDate.year) or currentYear
    local age = math.max(1, (currentMonth + (currentYear - 1) * 12) - (pMonth + (pYear - 1) * 12))
    
    local costPerMonth = totalCost / age
    local avgBreakdownInterval = totalBreakdowns > 0 and math.max(((self.vehicle:getFormattedOperatingTime() - (purchaseHours or 0)) / totalBreakdowns), 0) or 0
    local averageMaintenanceInterval = 0

    self.costPerMonthValue:setText(g_i18n:formatMoney(costPerMonth, 0, true, true) .. " / " .. g_i18n:getText("ads_ws_age_unit"))
    self.ownershipMonthsValue:setText(tostring(age) .. " " .. g_i18n:getText("ads_ws_age_unit"))
    self.totalBreakdownsCountValue:setText(string.format("%d", totalBreakdowns))
    if totalBreakdowns > 0 then
        self.averageBreakdownsIntervalValue:setText(string.format("%.1f", avgBreakdownInterval) .. " " .. g_i18n:getText("ads_spec_hour_s"))
    else
        self.averageBreakdownsIntervalValue:setText("-")
    end

    local maintenanceCount = 0
    for _, entry in pairs(self.logDataAll) do
        if entry.type == AdvancedDamageSystem.STATUS.MAINTENANCE then
            maintenanceCount = maintenanceCount + 1
        end
    end

    if maintenanceCount > 0 then
        local sumMaintenanceInterval = 0
        local lastServiceHours = purchaseHours or 0
        for i = 1, #self.logDataAll do
            local nextEntry = self.logDataAll[i]
            if nextEntry.type == AdvancedDamageSystem.STATUS.MAINTENANCE then
                if nextEntry.conditionData and nextEntry.conditionData.operatingHours then
                    sumMaintenanceInterval = sumMaintenanceInterval + (nextEntry.conditionData.operatingHours - lastServiceHours)
                    lastServiceHours = nextEntry.conditionData.operatingHours
                end
            end
        end
        averageMaintenanceInterval = math.max(sumMaintenanceInterval / maintenanceCount, 0)
        self.averageMaintenanceIntervalValue:setText(string.format("%.1f", averageMaintenanceInterval) .. " " .. g_i18n:getText("ads_spec_hour_s"))
    end

    self.logTable:setDataSource(self)
    self.logTable:setDelegate(self)
    self.logTable:reloadData()

    if #self.logData > 0 then
        if self.selectedLogIndex == nil or self.selectedLogIndex > #self.logData then
            self.selectedLogIndex = 1
        end
        self.logTable:setSelectedItem(1, self.selectedLogIndex, false, false)
    else
        self.selectedLogIndex = nil
    end

    self:updateShowReportButtonState()

    local isEmpty = #self.logData == 0
    self.logTable:setVisible(not isEmpty)
    self.emptylogText:setVisible(isEmpty)
end

-- ====================================================================
-- LIST DELEGATE METHODS
-- ====================================================================

function ADS_MaintenanceLogDialog:getNumberOfItemsInSection(list, section)
    return #self.logData
end

function ADS_MaintenanceLogDialog:populateCellForItemInSection(list, section, index, cell)
    local entryIndex = #self.logData - index + 1
    local entry = self.logData[entryIndex]
    local spec = self.vehicle.spec_AdvancedDamageSystem

    if entry == nil then return end

    -- date
    local yearStr = "00"
    if entry.date and entry.date.year then
        if entry.date.year >= 10 then
            yearStr = tostring(entry.date.year)
        else
            yearStr = "0" .. tostring(entry.date.year)
        end
    end
    local dDay = (entry.date and entry.date.day) or 1
    local dMonth = (entry.date and entry.date.month) or 1
    local dateStr = string.format("%s %s. '%s", dDay, g_i18n:formatPeriod(dMonth, true), yearStr)
    cell:getAttribute("logDate"):setText(dateStr)
    
    -- operating hours
    local opHours = (entry.conditionData and entry.conditionData.operatingHours) or 0
    cell:getAttribute("logHours"):setText(string.format("%.1f", opHours) .. " " .. g_i18n:getText("ads_spec_hour_s"))

    -- maintenance type
    local typeText = "UNKNOWN"
    local color = {1, 1, 1, 1}
    
    local S = AdvancedDamageSystem.STATUS
    if entry.type == S.REPAIR then
        typeText = g_i18n:getText("ads_ws_action_repair")
        color = {0.88, 0.12, 0.12, 1}
    elseif entry.type == S.MAINTENANCE then
        typeText = g_i18n:getText("ads_ws_action_maintenance")
        color = {0.2, 0.6, 1.0, 1}
    elseif entry.type == S.INSPECTION then
        typeText = g_i18n:getText("ads_ws_action_inspection")
        color = {1, 1, 1, 1}
    elseif entry.type == S.OVERHAUL then
        typeText = g_i18n:getText("ads_ws_action_overhaul")
        color = {1.0, 0.5, 0.0, 1}
    end
    
    cell:getAttribute("logType"):setText(typeText)
    cell:getAttribute("logType"):setTextColor(unpack(color))

    -- description
    local descText = ""
    local repairedParts = {}
    local seenParts = {}

    if entry.conditionData and entry.conditionData.selectedBreakdowns then
        for _, breakdownId in ipairs(entry.conditionData.selectedBreakdowns) do
            if isLoggableRepairBreakdownId(breakdownId) then
                local breakdownDef = ADS_Breakdowns.BreakdownRegistry[breakdownId]
                 
                local partKey = breakdownDef ~= nil and (breakdownDef.part or breakdownDef.system) or nil
                if partKey ~= nil then
                    if not seenParts[partKey] then
                        table.insert(repairedParts, partKey)
                        seenParts[partKey] = true
                    end
                end
            end
        end
    end

    local partsNames = {}
    if repairedParts and #repairedParts > 0 then
        for _, partKey in ipairs(repairedParts) do
            table.insert(partsNames, g_i18n:getText(partKey))
        end
    end
   
    if entry.isCompleted == false then
        descText = g_i18n:getText("ads_log_cancelled_desc")
    else
        -- repair
        if entry.type == S.REPAIR then
            local repairedPartsText = table.concat(partsNames, ", ")
            if repairedPartsText == "" then
                repairedPartsText = g_i18n:getText("ads_log_repair_desc_generic")
            end
            descText = repairedPartsText .. " (" .. g_i18n:getText(entry.optionTwo or "NONE") .. ")"

        -- maintenance
        elseif entry.type == S.MAINTENANCE then
            descText = string.format(g_i18n:getText("ads_log_performed"), g_i18n:getText(entry.optionOne) .. " " .. g_i18n:getText("ads_ws_task_maintenance"))
            descText = descText .. " (" .. g_i18n:getText(entry.optionTwo) .. ")"
            if #repairedParts > 0 then
                descText = descText .. ". " .. string.format(g_i18n:getText("ads_log_inspection_desc_with_breakdowns"), table.concat(partsNames, ", "))
            end

        -- inspection
        elseif entry.type == S.INSPECTION then
            descText = string.format(g_i18n:getText("ads_log_performed"), g_i18n:getText(entry.optionOne) .. " " .. g_i18n:getText("ads_ws_task_inspection"))
            if #repairedParts > 0 then
                descText = descText .. ". " .. string.format(g_i18n:getText("ads_log_inspection_desc_with_breakdowns"), table.concat(partsNames, ", "))
            else
                descText = descText .. ". " .. g_i18n:getText("ads_log_inspection_desc_no_breakdowns")
            end
        

        -- overhaul
        elseif entry.type == S.OVERHAUL then
            descText = string.format(g_i18n:getText("ads_log_performed"), g_i18n:getText(entry.optionOne) .. " " .. g_i18n:getText("ads_ws_task_overhaul"))
            if entry.optionThree then
                descText = descText .. ". " .. g_i18n:getText("ads_log_overhaul_desc_with_painting")
            end
        end
    end

    cell:getAttribute("logDescription"):setText(descText)
    
    cell:getAttribute("logPrice"):setText(g_i18n:formatMoney(entry.price or 0, 0, true, true))
    color = {0.88, 0.12, 0.12, 1}
    cell:getAttribute("logPrice"):setTextColor(unpack(color))
end

-- ====================================================================
-- CALLBACKS & EVENTS
-- ====================================================================

function ADS_MaintenanceLogDialog:onClickBack()
    self:close()
end

function ADS_MaintenanceLogDialog:onRowClick(row)
    if row == nil or row.indexInSection == nil then return end

    self.selectedLogIndex = row.indexInSection
    if self.logTable ~= nil then
        self.logTable:setSelectedItem(1, row.indexInSection, false, false)
    end
    self:updateShowReportButtonState()
end

function ADS_MaintenanceLogDialog:onClickShowReport()
    local entry = self:getSelectedLogEntry()
    if entry ~= nil and AdvancedDamageSystem.getIsLogEntryHasReport(entry) then
        ADS_ReportDialog.show(self.vehicle, entry)
        return
    end

    InfoDialog.show(g_i18n:getText("ads_ws_no_report_message"))
end

function ADS_MaintenanceLogDialog:onOpen(superFunc)
    g_messageCenter:subscribe(MessageType.MONEY_CHANGED, self.updateScreen, self)
end

function ADS_MaintenanceLogDialog:onClose(superFunc)
    self.vehicle = nil
    self.logData = nil
    self.logDataAll = nil
    self.selectedLogIndex = nil
    g_messageCenter:unsubscribeAll(self)
end
