--luacheck: ignore
local Functions = require 'maps.biter_battles_v2.functions'
local Gui = require 'maps.biter_battles_v2.gui'
local Init = require 'maps.biter_battles_v2.init'
local Score = require 'utils.gui.score'
local Server = require 'utils.server'
local Discord = require 'utils.discord'

-- Use these settings for live
local send_ping_to_channel = Discord.channel_names.bb_channel
local role_to_mention = Discord.role_mentions.biter_battles
-- Use these settings for testing
-- bot-lounge
-- local send_ping_to_channel = Discord.channel_names.bot_quarters
-- local role_to_mention = Discord.role_mentions.test_role

local Public = {}

local gui_values = {
    ['north'] = { c1 = 'Team North', color1 = { r = 0.55, g = 0.55, b = 0.99 } },
    ['south'] = { c1 = 'Team South', color1 = { r = 0.99, g = 0.33, b = 0.33 } }
}

function Public.reveal_map()
    for _, f in pairs({ 'north', 'south', 'player', 'spectator' }) do
        local r = 768
        game.forces[f].chart(game.surfaces['biter_battles'], { { r * -1, r * -1 }, { r, r } })
    end
end

local function create_victory_gui(player)
    local values = gui_values[storage.bb_game_won_by_team]
    local c = values.c1
    if storage.tm_custom_name[storage.bb_game_won_by_team] then
        c = storage.tm_custom_name[storage.bb_game_won_by_team]
    end
    local frame = player.gui.left.add { type = 'frame', name = 'bb_victory_gui', direction = 'vertical', caption = c .. ' won!' }
    frame.style.font = 'heading-1'
    frame.style.font_color = values.color1

    local l = frame.add { type = 'label', caption = storage.victory_time }
    l.style.font = 'heading-2'
    l.style.font_color = { r = 0.77, g = 0.77, b = 0.77 }
end

local function silo_kaboom(entity)
    local surface = entity.surface
    local center_position = entity.position
    local force = entity.force
    surface.create_entity(
        {
            name = 'atomic-rocket',
            position = center_position,
            force = force,
            source = center_position,
            target = center_position,
            max_range = 1,
            speed = 0.1
        }
    )

    local drops = {}
    for x = -32, 32, 1 do
        for y = -32, 32, 1 do
            local p = { x = center_position.x + x, y = center_position.y + y }
            local distance_to_silo = math.sqrt((center_position.x - p.x) ^ 2 + (center_position.y - p.y) ^ 2)
            local count = math.floor((32 - distance_to_silo * 1.2) * 0.28)
            if distance_to_silo < 32 and count > 0 then
                table.insert(drops, { p, count })
            end
        end
    end
    for _, drop in pairs(drops) do
        for _ = 1, drop[2], 1 do
            entity.surface.spill_item_stack({ drop[1].x + math.random(0, 9) * 0.1, drop[1].y + math.random(0, 9) * 0.1 }, { name = 'raw-fish', count = 1 }, false, nil, true)
        end
    end
end

local function get_sorted_list(column_name, score_list)
    for _ = 1, #score_list, 1 do
        for y = 1, #score_list, 1 do
            if not score_list[y + 1] then
                break
            end
            if score_list[y][column_name] < score_list[y + 1][column_name] then
                local key = score_list[y]
                score_list[y] = score_list[y + 1]
                score_list[y + 1] = key
            end
        end
    end
    return score_list
end

local function get_mvps(force)
    local get_score = Score.get_table().score_table
    if not get_score[force] then
        return false
    end
    local score = get_score[force]
    local score_list = {}
    for _, p in pairs(game.players) do
        if score.players[p.name] then
            local killscore = 0
            if score.players[p.name].killscore then
                killscore = score.players[p.name].killscore
            end
            local deaths = 0
            if score.players[p.name].deaths then
                deaths = score.players[p.name].deaths
            end
            local built_entities = 0
            if score.players[p.name].built_entities then
                built_entities = score.players[p.name].built_entities
            end
            local mined_entities = 0
            if score.players[p.name].mined_entities then
                mined_entities = score.players[p.name].mined_entities
            end
            table.insert(score_list, { name = p.name, killscore = killscore, deaths = deaths, built_entities = built_entities, mined_entities = mined_entities })
        end
    end
    local mvp = {}
    score_list = get_sorted_list('killscore', score_list)
    mvp.killscore = { name = score_list[1].name, score = score_list[1].killscore }
    score_list = get_sorted_list('deaths', score_list)
    mvp.deaths = { name = score_list[1].name, score = score_list[1].deaths }
    score_list = get_sorted_list('built_entities', score_list)
    mvp.built_entities = { name = score_list[1].name, score = score_list[1].built_entities }
    return mvp
end

local function show_mvps(player)
    local get_score = Score.get_table().score_table
    if not get_score then
        return
    end
    if player.gui.left['mvps'] then
        return
    end
    local frame = player.gui.left.add({ type = 'frame', name = 'mvps', direction = 'vertical' })
    local l = frame.add({ type = 'label', caption = 'MVPs - North:' })
    l.style.font = 'default-listbox'
    l.style.font_color = { r = 0.55, g = 0.55, b = 0.99 }

    local t = frame.add({ type = 'table', column_count = 2 })
    local mvp = get_mvps('north')
    if mvp then
        local l = t.add({ type = 'label', caption = 'Defender >> ' })
        l.style.font = 'default-listbox'
        l.style.font_color = { r = 0.22, g = 0.77, b = 0.44 }
        local l = t.add({ type = 'label', caption = mvp.killscore.name .. ' with a score of ' .. mvp.killscore.score })
        l.style.font = 'default-bold'
        l.style.font_color = { r = 0.33, g = 0.66, b = 0.9 }

        local l = t.add({ type = 'label', caption = 'Builder >> ' })
        l.style.font = 'default-listbox'
        l.style.font_color = { r = 0.22, g = 0.77, b = 0.44 }
        local l = t.add({ type = 'label', caption = mvp.built_entities.name .. ' built ' .. mvp.built_entities.score .. ' things' })
        l.style.font = 'default-bold'
        l.style.font_color = { r = 0.33, g = 0.66, b = 0.9 }

        local l = t.add({ type = 'label', caption = 'Deaths >> ' })
        l.style.font = 'default-listbox'
        l.style.font_color = { r = 0.22, g = 0.77, b = 0.44 }
        local l = t.add({ type = 'label', caption = mvp.deaths.name .. ' died ' .. mvp.deaths.score .. ' times' })
        l.style.font = 'default-bold'
        l.style.font_color = { r = 0.33, g = 0.66, b = 0.9 }

        if not storage.results_sent_north then
            local result = {}
            table.insert(result, 'NORTH: \\n')
            table.insert(result, 'MVP Defender: \\n')
            table.insert(result, mvp.killscore.name .. ' with a score of ' .. mvp.killscore.score .. '\\n')
            table.insert(result, '\\n')
            table.insert(result, 'MVP Builder: \\n')
            table.insert(result, mvp.built_entities.name .. ' built ' .. mvp.built_entities.score .. ' things\\n')
            table.insert(result, '\\n')
            table.insert(result, 'MVP Deaths: \\n')
            table.insert(result, mvp.deaths.name .. ' died ' .. mvp.deaths.score .. ' times')
            local message = table.concat(result)
            Server.to_discord_embed(message)
            storage.results_sent_north = true
        end
    end

    local l = frame.add({ type = 'label', caption = 'MVPs - South:' })
    l.style.font = 'default-listbox'
    l.style.font_color = { r = 0.99, g = 0.33, b = 0.33 }

    local t = frame.add({ type = 'table', column_count = 2 })
    local mvp = get_mvps('south')
    if mvp then
        local l = t.add({ type = 'label', caption = 'Defender >> ' })
        l.style.font = 'default-listbox'
        l.style.font_color = { r = 0.22, g = 0.77, b = 0.44 }
        local l = t.add({ type = 'label', caption = mvp.killscore.name .. ' with a score of ' .. mvp.killscore.score })
        l.style.font = 'default-bold'
        l.style.font_color = { r = 0.33, g = 0.66, b = 0.9 }

        local l = t.add({ type = 'label', caption = 'Builder >> ' })
        l.style.font = 'default-listbox'
        l.style.font_color = { r = 0.22, g = 0.77, b = 0.44 }
        local l = t.add({ type = 'label', caption = mvp.built_entities.name .. ' built ' .. mvp.built_entities.score .. ' things' })
        l.style.font = 'default-bold'
        l.style.font_color = { r = 0.33, g = 0.66, b = 0.9 }

        local l = t.add({ type = 'label', caption = 'Deaths >> ' })
        l.style.font = 'default-listbox'
        l.style.font_color = { r = 0.22, g = 0.77, b = 0.44 }
        local l = t.add({ type = 'label', caption = mvp.deaths.name .. ' died ' .. mvp.deaths.score .. ' times' })
        l.style.font = 'default-bold'
        l.style.font_color = { r = 0.33, g = 0.66, b = 0.9 }

        if not storage.results_sent_south then
            local result = {}
            table.insert(result, 'SOUTH: \\n')
            table.insert(result, 'MVP Defender: \\n')
            table.insert(result, mvp.killscore.name .. ' with a score of ' .. mvp.killscore.score .. '\\n')
            table.insert(result, '\\n')
            table.insert(result, 'MVP Builder: \\n')
            table.insert(result, mvp.built_entities.name .. ' built ' .. mvp.built_entities.score .. ' things\\n')
            table.insert(result, '\\n')
            table.insert(result, 'MVP Deaths: \\n')
            table.insert(result, mvp.deaths.name .. ' died ' .. mvp.deaths.score .. ' times')
            local message = table.concat(result)
            Server.to_discord_embed(message)
            storage.results_sent_south = true
        end
    end
end

local enemy_team_of = {
    ['north'] = 'south',
    ['south'] = 'north'
}

function Public.server_restart()
    if not storage.server_restart_timer then
        return
    end
    storage.server_restart_timer = storage.server_restart_timer - 5
    if storage.server_restart_timer == 150 then
        return
    end
    if storage.server_restart_timer == 10 then
        game.delete_surface(game.surfaces.bb_source)
        return
    end
    if storage.server_restart_timer == 5 then
        Init.source_surface()
        return
    end

    if storage.server_restart_timer == 0 then
        if storage.restart then
            if not storage.announced_message then
                local message = 'Soft-reset is disabled! Server will restart from scenario to load new changes.'
                game.print(message, { r = 0.22, g = 0.88, b = 0.22 })
                Server.to_discord_bold(table.concat { '*** ', message, ' ***' })
                Server.start_scenario('Biter_Battles')
                storage.announced_message = true
                return
            end
        end
        if storage.shutdown then
            if not storage.announced_message then
                local message = 'Soft-reset is disabled! Server will shutdown. Most likely because of updates.'
                game.print(message, { r = 0.22, g = 0.88, b = 0.22 })
                Server.to_discord_bold(table.concat { '*** ', message, ' ***' })
                Server.stop_scenario()
                storage.announced_message = true
                return
            end
        end
        game.print('Map is restarting!', { r = 0.22, g = 0.88, b = 0.22 })
        local message = 'Map is restarting! '
        Server.to_discord_bold(table.concat { '*** ', message, ' ***' })

        Server.to_discord_named_raw(send_ping_to_channel, role_to_mention .. ' ** Biter Battles was just reset! **')

        Init.tables()
        Init.forces()
        Init.load_spawn()
        for _, player in pairs(game.players) do
            Functions.init_player(player)
            for _, e in pairs(player.gui.left.children) do
                e.destroy()
            end
            Gui.create_main_gui(player)
        end
        game.surfaces.biter_battles.clear(true)
        game.reset_time_played()
        storage.server_restart_timer = nil
        game.speed = 1
        return
    end
    if storage.server_restart_timer % 30 == 0 then
        game.print('Map will restart in ' .. storage.server_restart_timer .. ' seconds!', { r = 0.22, g = 0.88, b = 0.22 })
    end
end

local function set_victory_time()
    local tick = game.ticks_played
    local minutes = tick % 216000
    local hours = tick - minutes
    minutes = math.floor(minutes / 3600)
    hours = math.floor(hours / 216000)
    if hours > 0 then
        hours = hours .. ' hours and '
    else
        hours = ''
    end
    storage.victory_time = 'Time - ' .. hours
    storage.victory_time = storage.victory_time .. minutes
    storage.victory_time = storage.victory_time .. ' minutes'
end

local function freeze_all_biters(surface)
    for _, e in pairs(surface.find_entities_filtered({ force = 'north_biters' })) do
        e.active = false
    end
    for _, e in pairs(surface.find_entities_filtered({ force = 'south_biters' })) do
        e.active = false
    end
end

local function biter_killed_the_silo(event)
    local cause = event.cause
    if cause and cause.valid and cause.type == 'unit' then
        return true
    end
    return
end

function Public.silo_death(event)
    local entity = event.entity
    if not entity.valid then
        return
    end
    if entity.name ~= 'rocket-silo' then
        return
    end
    if storage.bb_game_won_by_team then
        return
    end
    if entity == storage.rocket_silo.south or entity == storage.rocket_silo.north then
        --Respawn Silo in case of friendly fire
        if not biter_killed_the_silo(event) then
            storage.rocket_silo[entity.force.name] = entity.clone({ position = entity.position, surface = entity.surface, force = entity.force })
            storage.rocket_silo[entity.force.name].health = 5
            return
        end

        storage.bb_game_won_by_team = enemy_team_of[entity.force.name]

        set_victory_time()

        for _, player in pairs(game.connected_players) do
            player.play_sound { path = 'utility/game_won', volume_modifier = 1 }
            if player.gui.left['bb_main_gui'] then
                player.gui.left['bb_main_gui'].visible = false
            end
            create_victory_gui(player)
            show_mvps(player)
            --[[
			player.set_controller({
				type = defines.controllers.cutscene,
				waypoints = {{position = {event.entity.position.x, event.entity.position.y},
				transition_time = 0,
				time_to_wait = 900,
				zoom = 0.5}},
				start_position = {player.position.x, player.position.y},
				start_zoom = 1,
				final_transition_time = 180
			})
			]]
        end

        storage.spy_fish_timeout['north'] = game.tick + 999999
        storage.spy_fish_timeout['south'] = game.tick + 999999
        storage.server_restart_timer = 150

        local c = gui_values[storage.bb_game_won_by_team].c1
        if storage.tm_custom_name[storage.bb_game_won_by_team] then
            c = storage.tm_custom_name[storage.bb_game_won_by_team]
        end

        Server.to_discord_embed(c .. ' has won!')
        Server.to_discord_embed(storage.victory_time)

        silo_kaboom(entity)

        freeze_all_biters(entity.surface)
    end
end

return Public
