local battleGeneral = require("scripts/battleGeneral")
local battlePlayer = require("scripts/battlePlayer")
local battlePhanto = require("scripts/battlePhanto")
local battleBombs = require("scripts/battleBombs")
local battleHUD = require("scripts/battleHUD")
local battleMap = require("scripts/battleMap")
local battleMenu = require("scripts/battleMenu")

local textplus = require("textplus")
local easing = require("ext/easing")

local killFeed = {}


killFeed.messageLifetime = 192
killFeed.messageFadeInTime = 12
killFeed.messageFadeOutTime = 12

killFeed.boxImage = Graphics.loadImageResolved("resources/hud/killFeed/box.png")
killFeed.boxMarginX = 4
killFeed.boxMarginY = 3

killFeed.textOffsetY = 1

killFeed.gap = 4
killFeed.messageGap = 4

killFeed.textFormat = {font = textplus.loadFont("resources/font/mainFont.ini"),xscale = 1,yscale = 1}


killFeed.causeIconNames = {
    [battlePlayer.HARM_CAUSE.PLAYER_STOMP] = "boot",
    [battlePlayer.HARM_CAUSE.PLAYER_SLIDE] = "slide",
    [battlePlayer.HARM_CAUSE.PLAYER_STATUE_STOMP] = "tanookiStatue",
    [battlePlayer.HARM_CAUSE.PLAYER_STATUE_SLIDE] = "tanookiStatue",
    [battlePlayer.HARM_CAUSE.PLAYER_SWORD] = "sword",
    [battlePlayer.HARM_CAUSE.PLAYER_STARMAN] = "star",

    [battlePlayer.HARM_CAUSE.EXPLOSION] = "explosion",
}

killFeed.npcIconNames = {
    [13] = "fireball",
    [265] = "iceball",
    [171] = "hammer",
    [291] = "bomb",
    [292] = "boomerang",
    [266] = "sword",
    [955] = "stone",
    [958] = "phanto",
}


killFeed.icons = {}

killFeed.messages = {}


function killFeed.formatPlayerName(playerIndex)
    return string.format("<color %s>%s</color>",tostring(battlePlayer.getColor(playerIndex)),battleGeneral.escapeTextplusTags(battlePlayer.getName(playerIndex)))
end


function killFeed.isEnabled()
    if battleGeneral.isInHub then
        return false
    end

    local fullRuleset = battleOptions.getFullRuleset()

    return fullRuleset.general.killFeedEnabled
end


function killFeed.getPosition(camIdx)
    local cam = Camera(camIdx)

    local screenWidth,screenHeight = battleGeneral.getScreenSize()

    -- Split-screen
    if battleCamera.splitMode == battleCamera.SPLIT_MODE.VERTICAL then
        local x = screenWidth*0.5 - cam.renderX
        local y = screenHeight - battleHUD.normalPadding - cam.renderY

        if not battleGeneral.disableMap then
            local _,mapHeightA = battleMap.getSize(1)
            local _,mapHeightB = battleMap.getSize(2)

            y = y - battleHUD.normalPadding*0.5 - math.max(mapHeightA,mapHeightB)
        end

        return x,y,0.5,false
    elseif battleCamera.splitMode == battleCamera.SPLIT_MODE.HORIZONTAL then
        local x = screenWidth - battleHUD.normalPadding - cam.renderX
        local y = screenHeight*0.5 - cam.renderY

        if not battleGeneral.disableMap then
            local mapWidthA,_ = battleMap.getSize(1)
            local mapWidthB,_ = battleMap.getSize(2)

            x = x - battleHUD.normalPadding*0.5 - math.max(mapWidthA,mapWidthB)
        end

        return x,y,0.5,true
    end

    -- Single-screen
    if (camIdx == 2) ~= battleCamera.wrapSeamIsVisible then
        return nil
    end

    local x = screenWidth - battleHUD.normalPadding - cam.renderX
    local y = screenHeight - battleHUD.normalPadding - cam.renderY

    if not battleGeneral.disableMap then
        local mapWidth,mapHeight = battleMap.getSize(1)

        if mapHeight > mapWidth*1.5 then
            x = x - battleHUD.normalPadding*0.5 - mapWidth
        else
            y = y - battleHUD.normalPadding*0.5 - mapHeight
        end
    end

    return x,y,1,false
end


function killFeed.addMessage(leftText,rightText,iconImage)
    if not killFeed.isEnabled() then
        return
    end

    local message = {}
    
    message.mainWidth = 0
    message.mainHeight = 0

    local gap = 0

    if leftText ~= nil then
        message.leftTextLayout = textplus.layout(leftText,nil,killFeed.textFormat)
        message.leftTextX = message.mainWidth + gap

        message.mainWidth = message.mainWidth + message.leftTextLayout.width + gap
        message.mainHeight = math.max(message.mainHeight,message.leftTextLayout.height)

        gap = killFeed.gap
    end

    if iconImage ~= nil then
        message.iconImage = iconImage
        message.iconX = message.mainWidth + gap

        message.mainWidth = message.mainWidth + message.iconImage.width + gap
        message.mainHeight = math.max(message.mainHeight,message.iconImage.height)

        gap = killFeed.gap
    end

    if rightText ~= nil then
        message.rightTextLayout = textplus.layout(rightText,nil,killFeed.textFormat)
        message.rightTextX = message.mainWidth + gap

        message.mainWidth = message.mainWidth + message.rightTextLayout.width + gap
        message.mainHeight = math.max(message.mainHeight,message.rightTextLayout.height)

        gap = killFeed.gap
    end

    message.mainWidth = math.ceil(message.mainWidth*0.5)*2
    message.mainHeight = math.ceil(message.mainHeight*0.5)*2

    message.totalWidth = message.mainWidth + killFeed.boxMarginX*2
    message.totalHeight = message.mainHeight + killFeed.boxMarginY*2

    message.timer = 0
    
    table.insert(killFeed.messages,message)

    return message
end

function killFeed.addInterplayerHarmMessage(attackerPlayerIdx,defenderPlayerIdx,iconImage)
    return killFeed.addMessage(killFeed.formatPlayerName(attackerPlayerIdx),killFeed.formatPlayerName(defenderPlayerIdx),iconImage)
end

function killFeed.addSelfInflectedHarmMessage(playerIdx,iconImage)
    return killFeed.addMessage(nil,killFeed.formatPlayerName(playerIdx),iconImage)
end


local function drawMessage(message,x,y,opacity)
    local mainX = x + killFeed.boxMarginX
    local mainY = y + killFeed.boxMarginY

    local textColor = Color.white*opacity

    battleMenu.drawSegmentedBox{
        texture = killFeed.boxImage,
        color = Color.white.. opacity,
        priority = battleHUD.priority,
        x = x,
        y = y,
        width = message.totalWidth,
        height = message.totalHeight,
    }

    if message.leftTextLayout ~= nil then
        textplus.render{
            layout = message.leftTextLayout,
            priority = battleHUD.priority,
            color = textColor,
            x = mainX + message.leftTextX,
            y = mainY + message.mainHeight - message.leftTextLayout.height + killFeed.textOffsetY,
        }
    end

    if message.iconImage ~= nil then
        Graphics.drawBox{
            texture = message.iconImage,
            priority = battleHUD.priority,
            color = Color.white.. opacity,
            x = mainX + message.iconX,
            y = mainY + math.ceil((message.mainHeight - message.iconImage.height)*0.5),
        }
    end

    if message.rightTextLayout ~= nil then
        textplus.render{
            layout = message.rightTextLayout,
            priority = battleHUD.priority,
            color = textColor,
            x = mainX + message.rightTextX,
            y = mainY + message.mainHeight - message.rightTextLayout.height + killFeed.textOffsetY,
        }
    end
end


local function loadIcons(path)
    for _,filename in ipairs(Misc.listFiles(path)) do
        local name,extension = filename:match("^(.*)%.(.+)$")

        if extension == "png" then
            killFeed.icons[name] = Graphics.loadImage(path.. filename)
        end
    end
end

function killFeed.onStart()
    loadIcons(Misc.episodePath().. "resources/hud/killFeed/icons/")
    loadIcons(Misc.levelPath().. "resources/hud/killFeed/icons/")
end

function killFeed.onTick()
    if not killFeed.isEnabled() then
        return
    end

    local i = 1

    while (killFeed.messages[i] ~= nil) do
        local message = killFeed.messages[i]

        message.timer = message.timer + 1

        if message.timer >= killFeed.messageLifetime then
            table.remove(killFeed.messages,i)
        else
            i = i + 1
        end
    end
end

function killFeed.onCameraDraw(camIdx)
    if not killFeed.isEnabled() or battleHUD.disabled or battleHUD.opacity <= 0 then
        return
    end

    local baseX,baseY,align,isHorizontal = killFeed.getPosition(camIdx)

    if baseX == nil then
        return
    end

    local x = baseX
    local y = baseY

    for i = #killFeed.messages,1,-1 do
        local message = killFeed.messages[i]

        local fadeInTime = math.min(1,message.timer/killFeed.messageFadeInTime)
        local fadeOutTime = math.min(1,(killFeed.messageLifetime - message.timer)/killFeed.messageFadeOutTime)
        
        local opacity = fadeInTime*fadeOutTime*battleHUD.opacity
    
        if isHorizontal then
            drawMessage(message,x - message.totalWidth,y - message.totalHeight*align,opacity)
            x = x - (message.totalWidth + killFeed.messageGap)*easing.outQuad(fadeInTime,0,1,1)
        else
            drawMessage(message,x - message.totalWidth*align,y - message.totalHeight,opacity)
            y = y - (message.totalHeight + killFeed.messageGap)*easing.outQuad(fadeInTime,0,1,1)
        end
    end
end


local function getIconNameFromCauseInfo(causeInfo)
    if causeInfo.cause == battlePlayer.HARM_CAUSE.NPC then
        if killFeed.npcIconNames[causeInfo.npcID] ~= nil then
            return killFeed.npcIconNames[causeInfo.npcID]
        end

        if causeInfo.isProjectile then
            return "thrownNPC"
        end

        if causeInfo.npcID ~= nil and NPC.config[causeInfo.npcID].isshell then
            return "shell"
        end

        return "genericNPC"
    end

    if killFeed.causeIconNames[causeInfo.cause] ~= nil then
        return killFeed.causeIconNames[causeInfo.cause]
    end

    return "generic"
end

function battlePlayer.onPostPlayerHarmCustom(p,harmType,causeInfo)
    if not killFeed.isEnabled() then
        return
    end

    local iconImage = killFeed.icons[getIconNameFromCauseInfo(causeInfo)]

    if causeInfo.playerIdx ~= nil and causeInfo.playerIdx > 0 and causeInfo.playerIdx ~= p.idx then
        killFeed.addInterplayerHarmMessage(causeInfo.playerIdx,p.idx,iconImage)
    else
        killFeed.addSelfInflectedHarmMessage(p.idx,iconImage)
    end
end

function battlePlayer.onPostPlayerKillCustom(p)
    if not killFeed.isEnabled() then
        return
    end

    if p.y >= (p.sectionObj.boundary.bottom + 64) then
        killFeed.addSelfInflectedHarmMessage(p.idx,killFeed.icons.pit)
    end
end

function battleBombs.onExplosionHit(hitPlayer,bomberPlayer)
    if not killFeed.isEnabled() then
        return
    end

    killFeed.addInterplayerHarmMessage(bomberPlayer.idx,hitPlayer.idx,killFeed.icons.explosion)
end

function battlePhanto.onTransferMask(receiverPlayer,giverPlayer)
    if not killFeed.isEnabled() then
        return
    end

    killFeed.addInterplayerHarmMessage(giverPlayer.idx,receiverPlayer.idx,killFeed.icons.phantoTransfer)
end


function killFeed.onInitAPI()
    registerEvent(killFeed,"onStart")
    registerEvent(killFeed,"onTick")
    registerEvent(killFeed,"onCameraDraw")
end


return killFeed