--antigrief things made by mewmew

local Event = require 'utils.event'
local Jailed = require 'utils.datastore.jail_data'
local Tabs = require 'comfy_panel.main'
local AntiGrief = require 'antigrief'
local SpamProtection = require 'utils.spam_protection'
local Token = require 'utils.token'

local lower = string.lower
local module_name = 'Admin'

local function admin_only_message(str)
    for _, player in pairs(game.connected_players) do
        if player.admin == true then
            player.print('Admins-only-message: ' .. str, {r = 0.88, g = 0.88, b = 0.88})
        end
    end
end

local function jail(player, source_player)
    if player.name == source_player.name then
        return player.print("You can't select yourself!", {r = 1, g = 0.5, b = 0.1})
    end
    Jailed.try_ul_data(player.name, true, source_player.name, 'Jailed by script!')
end

local function free(player, source_player)
    if player.name == source_player.name then
        return player.print("You can't select yourself!", {r = 1, g = 0.5, b = 0.1})
    end
    Jailed.try_ul_data(player.name, false, source_player.name)
end

local bring_player_messages = {
    'Come here my friend!',
    'Papers, please.',
    'What are you up to?'
}

local function bring_player(player, source_player)
    if player.name == source_player.name then
        return player.print("You can't select yourself!", {r = 1, g = 0.5, b = 0.1})
    end
    if player.driving == true then
        source_player.print('Target player is in a vehicle, teleport not available.', {r = 0.88, g = 0.88, b = 0.88})
        return
    end
    local pos = source_player.surface.find_non_colliding_position('character', source_player.position, 50, 1)
    if pos then
        player.teleport(pos, source_player.surface)
        game.print(
            player.name .. ' has been teleported to ' .. source_player.name .. '. ' .. bring_player_messages[math.random(1, #bring_player_messages)],
            {r = 0.98, g = 0.66, b = 0.22}
        )
    end
end

local go_to_player_messages = {
    'Papers, please.',
    'What are you up to?'
}
local function go_to_player(player, source_player)
    if player.name == source_player.name then
        return player.print("You can't select yourself!", {r = 1, g = 0.5, b = 0.1})
    end
    local pos = player.surface.find_non_colliding_position('character', player.position, 50, 1)
    if pos then
        source_player.teleport(pos, player.surface)
        game.print(source_player.name .. ' is visiting ' .. player.name .. '. ' .. go_to_player_messages[math.random(1, #go_to_player_messages)], {r = 0.98, g = 0.66, b = 0.22})
    end
end

local function spank(player, source_player)
    if player.name == source_player.name then
        return player.print("You can't select yourself!", {r = 1, g = 0.5, b = 0.1})
    end
    if player.character then
        if player.character.health > 1 then
            player.character.damage(1, 'player')
        end
        player.character.health = player.character.health - 5
        player.surface.create_entity({name = 'water-splash', position = player.position})
        game.print(source_player.name .. ' spanked ' .. player.name, {r = 0.98, g = 0.66, b = 0.22})
    end
end

local damage_messages = {
    ' recieved a love letter from ',
    ' recieved a strange package from '
}
local function damage(player, source_player)
    if player.name == source_player.name then
        return player.print("You can't select yourself!", {r = 1, g = 0.5, b = 0.1})
    end
    if player.character then
        if player.character.health > 1 then
            player.character.damage(1, 'player')
        end
        player.character.health = player.character.health - 125
        player.surface.create_entity({name = 'big-explosion', position = player.position})
        game.print(player.name .. damage_messages[math.random(1, #damage_messages)] .. source_player.name, {r = 0.98, g = 0.66, b = 0.22})
    end
end

local kill_messages = {
    ' did not obey the law.',
    ' should not have triggered the admins.',
    ' did not respect authority.',
    ' had a strange accident.',
    ' was struck by lightning.'
}
local function kill(player, source_player)
    if player.name == source_player.name then
        return player.print("You can't select yourself!", {r = 1, g = 0.5, b = 0.1})
    end
    if player.character then
        player.character.die('player')
        game.print(player.name .. kill_messages[math.random(1, #kill_messages)], {r = 0.98, g = 0.66, b = 0.22})
        admin_only_message(source_player.name .. ' killed ' .. player.name)
    end
end

local enemy_messages = {
    'Shoot on sight!',
    'Wanted dead or alive!'
}
local function enemy(player, source_player)
    if player.name == source_player.name then
        return player.print("You can't select yourself!", {r = 1, g = 0.5, b = 0.1})
    end
    if not game.forces.enemy_players then
        game.create_force('enemy_players')
    end
    player.force = game.forces.enemy_players
    game.print(player.name .. ' is now an enemy! ' .. enemy_messages[math.random(1, #enemy_messages)], {r = 0.95, g = 0.15, b = 0.15})
    admin_only_message(source_player.name .. ' has turned ' .. player.name .. ' into an enemy')
end

local function ally(player, source_player)
    if player.name == source_player.name then
        return player.print("You can't select yourself!", {r = 1, g = 0.5, b = 0.1})
    end
    player.force = game.forces.player
    game.print(player.name .. ' is our ally again!', {r = 0.98, g = 0.66, b = 0.22})
    admin_only_message(source_player.name .. ' made ' .. player.name .. ' our ally')
end

local function turn_off_global_speakers(player)
    local counter = 0
    for _, surface in pairs(game.surfaces) do
        local speakers = surface.find_entities_filtered({name = 'programmable-speaker'})
        for i, speaker in pairs(speakers) do
            if speaker.parameters.playback_globally == true then
                speaker.surface.create_entity({name = 'massive-explosion', position = speaker.position})
                speaker.die('player')
                counter = counter + 1
            end
        end
    end
    if counter == 0 then
        return
    end
    if counter == 1 then
        game.print(player.name .. ' has nuked ' .. counter .. ' global speaker.', {r = 0.98, g = 0.66, b = 0.22})
    else
        game.print(player.name .. ' has nuked ' .. counter .. ' global speakers.', {r = 0.98, g = 0.66, b = 0.22})
    end
end

local function delete_all_blueprints(player)
    local counter = 0
    for _, surface in pairs(game.surfaces) do
        for _, ghost in pairs(surface.find_entities_filtered({type = {'entity-ghost', 'tile-ghost'}})) do
            ghost.destroy()
            counter = counter + 1
        end
    end
    if counter == 0 then
        return
    end
    if counter == 1 then
        game.print(counter .. ' blueprint has been cleared!', {r = 0.98, g = 0.66, b = 0.22})
    else
        game.print(counter .. ' blueprints have been cleared!', {r = 0.98, g = 0.66, b = 0.22})
    end
    admin_only_message(player.name .. ' has cleared all blueprints.')
end

local function create_mini_camera_gui(player, caption, position, surface)
    if player.gui.center['mini_camera'] then
        player.gui.center['mini_camera'].destroy()
    end
    local frame = player.gui.center.add({type = 'frame', name = 'mini_camera', caption = caption})
    surface = tonumber(surface)
    surface = game.surfaces[surface]
    if not surface or not surface.valid then
        return
    end

    local camera =
        frame.add(
        {
            type = 'camera',
            name = 'mini_cam_element',
            position = position,
            zoom = 0.6,
            surface_index = surface.index
        }
    )
    camera.style.minimal_width = 640
    camera.style.minimal_height = 480
end

local function filter_brackets(str)
    return (string.find(str, '%[') ~= nil)
end

local function match_test(value, pattern)
    return lower(value:gsub('-', ' ')):find(pattern)
end

local function contains_text(key, value, search_text)
    if filter_brackets(search_text) then
        return false
    end
    if value then
        if not match_test(key[value], search_text) then
            return false
        end
    else
        if not match_test(key, search_text) then
            return false
        end
    end
    return true
end

local function draw_events(data)
    local frame = data.frame
    local antigrief = data.antigrief
    local search_text = data.search_text or nil
    local history = frame['admin_history_select'].items[frame['admin_history_select'].selected_index]

    local history_index = {
        ['Capsule History'] = antigrief.capsule_history,
        ['Message History'] = antigrief.message_history,
        ['Friendly Fire History'] = antigrief.friendly_fire_history,
        ['Mining History'] = antigrief.mining_history,
        ['Mining Override History'] = antigrief.whitelist_mining_history,
        ['Landfill History'] = antigrief.landfill_history,
        ['Corpse Looting History'] = antigrief.corpse_history,
        ['Cancel Crafting History'] = antigrief.cancel_crafting_history
    }

    local scroll_pane
    if frame.datalog then
        frame.datalog.clear()
    else
        scroll_pane =
            frame.add(
            {
                type = 'scroll-pane',
                name = 'datalog',
                direction = 'vertical',
                horizontal_scroll_policy = 'never',
                vertical_scroll_policy = 'auto'
            }
        )
        scroll_pane.style.maximal_height = 200
        scroll_pane.style.minimal_width = 790
    end

    local tooltip = 'Click to open mini camera.'

    local target_player_name = frame['admin_player_select'].items[frame['admin_player_select'].selected_index]
    if game.players[target_player_name] then
        if not history_index or not history_index[history] or #history_index[history] <= 0 then
            return
        end

        for i = #history_index[history], 1, -1 do
            if history_index[history][i]:find(target_player_name) then
                if search_text then
                    local success = contains_text(history_index[history][i], nil, search_text)
                    if not success then
                        goto continue
                    end
                end

                if history == 'Message History' then
                    tooltip = ''
                end

                frame.datalog.add(
                    {
                        type = 'label',
                        caption = history_index[history][i],
                        tooltip = tooltip
                    }
                )
                ::continue::
            end
        end
    else
        for i = #history_index[history], 1, -1 do
            if search_text then
                local success = contains_text(history_index[history][i], nil, search_text)
                if not success then
                    goto continue
                end
            end

            frame.datalog.add(
                {
                    type = 'label',
                    caption = history_index[history][i],
                    tooltip = 'Click to open mini camera.'
                }
            )
            ::continue::
        end
    end
end

local function text_changed(event)
    local element = event.element
    if not element then
        return
    end
    if not element.valid then
        return
    end

    local antigrief = AntiGrief.get()
    local player = game.players[event.player_index]

    local frame = Tabs.comfy_panel_get_active_frame(player)
    if not frame then
        return
    end
    if frame.name ~= module_name then
        return
    end

    local is_spamming = SpamProtection.is_spamming(player, nil, 'Admin Text Changed')
    if is_spamming then
        return
    end

    local data = {
        frame = frame,
        antigrief = antigrief,
        search_text = element.text
    }

    draw_events(data)
end

local function create_admin_panel(data)
    local player = data.player
    local frame = data.frame
    local antigrief = AntiGrief.get()
    frame.clear()

    local player_names = {}
    for _, p in pairs(game.connected_players) do
        table.insert(player_names, tostring(p.name))
    end
    table.insert(player_names, 'Select Player')

    local selected_index = #player_names
    if global.admin_panel_selected_player_index then
        if global.admin_panel_selected_player_index[player.name] then
            if player_names[global.admin_panel_selected_player_index[player.name]] then
                selected_index = global.admin_panel_selected_player_index[player.name]
            end
        end
    end

    local drop_down = frame.add({type = 'drop-down', name = 'admin_player_select', items = player_names, selected_index = selected_index})
    drop_down.style.minimal_width = 326
    drop_down.style.right_padding = 12
    drop_down.style.left_padding = 12

    local t = frame.add({type = 'table', column_count = 3})
    local buttons = {
        t.add(
            {
                type = 'button',
                caption = 'Jail',
                name = 'jail',
                tooltip = 'Jails the player, they will no longer be able to perform any actions except writing in chat.'
            }
        ),
        t.add({type = 'button', caption = 'Free', name = 'free', tooltip = 'Frees the player from jail.'}),
        t.add(
            {
                type = 'button',
                caption = 'Bring Player',
                name = 'bring_player',
                tooltip = 'Teleports the selected player to your position.'
            }
        ),
        t.add(
            {
                type = 'button',
                caption = 'Make Enemy',
                name = 'enemy',
                tooltip = 'Sets the selected players force to enemy_players.          DO NOT USE IN PVP MAPS!!'
            }
        ),
        t.add(
            {
                type = 'button',
                caption = 'Make Ally',
                name = 'ally',
                tooltip = 'Sets the selected players force back to the default player force.           DO NOT USE IN PVP MAPS!!'
            }
        ),
        t.add(
            {
                type = 'button',
                caption = 'Go to Player',
                name = 'go_to_player',
                tooltip = 'Teleport yourself to the selected player.'
            }
        ),
        t.add(
            {
                type = 'button',
                caption = 'Spank',
                name = 'spank',
                tooltip = 'Hurts the selected player with minor damage. Can not kill the player.'
            }
        ),
        t.add(
            {
                type = 'button',
                caption = 'Damage',
                name = 'damage',
                tooltip = 'Damages the selected player with greater damage. Can not kill the player.'
            }
        ),
        t.add({type = 'button', caption = 'Kill', name = 'kill', tooltip = 'Kills the selected player instantly.'})
    }
    for _, button in pairs(buttons) do
        button.style.font = 'default-bold'
        --button.style.font_color = { r=0.99, g=0.11, b=0.11}
        button.style.font_color = {r = 0.99, g = 0.99, b = 0.99}
        button.style.minimal_width = 106
    end

    local line = frame.add {type = 'line'}
    line.style.top_margin = 8
    line.style.bottom_margin = 8

    frame.add({type = 'label', caption = 'Global Actions:'})
    local actionTable = frame.add({type = 'table', column_count = 2})
    local bottomButtons = {
        actionTable.add(
            {
                type = 'button',
                caption = 'Destroy global speakers',
                name = 'turn_off_global_speakers',
                tooltip = 'Destroys all speakers that are set to play sounds globally.'
            }
        ),
        actionTable.add(
            {
                type = 'button',
                caption = 'Delete blueprints',
                name = 'delete_all_blueprints',
                tooltip = 'Deletes all placed blueprints on the map.'
            }
        )
        ---	t.add({type = "button", caption = "Cancel all deconstruction orders", name = "remove_all_deconstruction_orders"})
    }
    for _, button in pairs(bottomButtons) do
        button.style.font = 'default-bold'
        button.style.font_color = {r = 0.98, g = 0.66, b = 0.22}
        button.style.minimal_width = 80
    end

    local bottomLine = frame.add {type = 'line'}
    bottomLine.style.top_margin = 8
    bottomLine.style.bottom_margin = 8

    local histories = {}
    if antigrief.capsule_history then
        table.insert(histories, 'Capsule History')
    end
    if antigrief.message_history then
        table.insert(histories, 'Message History')
    end
    if antigrief.friendly_fire_history then
        table.insert(histories, 'Friendly Fire History')
    end
    if antigrief.mining_history then
        table.insert(histories, 'Mining History')
    end
    if antigrief.whitelist_mining_history then
        table.insert(histories, 'Mining Override History')
    end
    if antigrief.landfill_history then
        table.insert(histories, 'Landfill History')
    end
    if antigrief.corpse_history then
        table.insert(histories, 'Corpse Looting History')
    end
    if antigrief.cancel_crafting_history then
        table.insert(histories, 'Cancel Crafting History')
    end

    if #histories == 0 then
        return
    end

    local search_table = frame.add({type = 'table', column_count = 2})
    search_table.add({type = 'label', caption = 'Search: '})
    local search_text = search_table.add({type = 'textfield'})
    search_text.style.width = 140

    local bottomLine2 = frame.add({type = 'label', caption = '----------------------------------------------'})
    bottomLine2.style.font = 'default-listbox'
    bottomLine2.style.font_color = {r = 0.98, g = 0.66, b = 0.22}

    local selected_index_2 = 1
    if global.admin_panel_selected_history_index then
        if global.admin_panel_selected_history_index[player.name] then
            selected_index_2 = global.admin_panel_selected_history_index[player.name]
        end
    end

    local drop_down_2 = frame.add({type = 'drop-down', name = 'admin_history_select', items = histories, selected_index = selected_index_2})
    drop_down_2.style.right_padding = 12
    drop_down_2.style.left_padding = 12

    local datas = {
        frame = frame,
        antigrief = antigrief
    }

    draw_events(datas)
end

local create_admin_panel_token = Token.register(create_admin_panel)

local admin_functions = {
    ['jail'] = jail,
    ['free'] = free,
    ['bring_player'] = bring_player,
    ['spank'] = spank,
    ['damage'] = damage,
    ['kill'] = kill,
    ['enemy'] = enemy,
    ['ally'] = ally,
    ['go_to_player'] = go_to_player
}

local admin_global_functions = {
    ['turn_off_global_speakers'] = turn_off_global_speakers,
    ['delete_all_blueprints'] = delete_all_blueprints
}

local function get_surface_from_string(str)
    if not str then
        return
    end
    if str == '' then
        return
    end
    str = string.lower(str)
    local start = string.find(str, 'surface:')
    local sname = string.len(str)
    local surface = string.sub(str, start + 8, sname)
    if not surface then
        return false
    end

    return surface
end

local function get_position_from_string(str)
    if not str then
        return
    end
    if str == '' then
        return
    end
    str = string.lower(str)
    local x_pos = string.find(str, 'x:')
    local y_pos = string.find(str, 'y:')
    if not x_pos then
        return false
    end
    if not y_pos then
        return false
    end
    x_pos = x_pos + 2
    y_pos = y_pos + 2

    local a = 1
    for i = 1, string.len(str), 1 do
        local s = string.sub(str, x_pos + i, x_pos + i)
        if not s then
            break
        end
        if string.byte(s) == 32 then
            break
        end
        a = a + 1
    end
    local x = string.sub(str, x_pos, x_pos + a)

    local a1 = 1
    for i = 1, string.len(str), 1 do
        local s = string.sub(str, y_pos + i, y_pos + i)
        if not s then
            break
        end
        if string.byte(s) == 32 then
            break
        end
        a1 = a1 + 1
    end

    local y = string.sub(str, y_pos, y_pos + a1)
    x = tonumber(x)
    y = tonumber(y)
    local position = {x = x, y = y}
    return position
end

local function on_gui_click(event)
    local element = event.element
    if not element or not element.valid then
        return
    end
    local player = game.get_player(event.player_index)

    local name = event.element.name

    if name == 'tab_Admin' then
        local is_spamming = SpamProtection.is_spamming(player, nil, 'Admin tab_Admin')
        if is_spamming then
            return
        end
    end

    local frame = Tabs.comfy_panel_get_active_frame(player)
    if not frame then
        return
    end

    if name == 'mini_camera' or name == 'mini_cam_element' then
        player.gui.center['mini_camera'].destroy()
        return
    end

    if frame.name ~= module_name then
        return
    end

    local is_spamming = SpamProtection.is_spamming(player, nil, 'Admin Gui Click')
    if is_spamming then
        return
    end

    if admin_functions[name] then
        local target_player_name = frame['admin_player_select'].items[frame['admin_player_select'].selected_index]
        if not target_player_name then
            return
        end
        if target_player_name == 'Select Player' then
            player.print('No target player selected.', {r = 0.88, g = 0.88, b = 0.88})
            return
        end
        local target_player = game.players[target_player_name]
        if target_player.connected == true then
            admin_functions[name](target_player, player)
        end
        return
    end

    if admin_global_functions[name] then
        admin_global_functions[name](player)
        return
    end

    if not frame then
        return
    end
    if not element.caption then
        return
    end
    local position = get_position_from_string(element.caption)
    if not position then
        return
    end

    local surface = get_surface_from_string(element.caption)
    if not surface then
        return
    end

    if player.gui.center['mini_camera'] then
        if player.gui.center['mini_camera'].caption == element.caption then
            player.gui.center['mini_camera'].destroy()
            return
        end
    end

    create_mini_camera_gui(player, element.caption, position, surface)
end

local function on_gui_selection_state_changed(event)
    local player = game.players[event.player_index]
    local name = event.element.name

    if name == 'admin_history_select' then
        if not global.admin_panel_selected_history_index then
            global.admin_panel_selected_history_index = {}
        end
        global.admin_panel_selected_history_index[player.name] = event.element.selected_index

        local frame = Tabs.comfy_panel_get_active_frame(player)
        if not frame then
            return
        end
        if frame.name ~= module_name then
            return
        end

        local is_spamming = SpamProtection.is_spamming(player, nil, 'Admin Selection Changed')
        if is_spamming then
            return
        end
        local data = {player = player, frame = frame}
        create_admin_panel(data)
    end
    if name == 'admin_player_select' then
        if not global.admin_panel_selected_player_index then
            global.admin_panel_selected_player_index = {}
        end
        global.admin_panel_selected_player_index[player.name] = event.element.selected_index

        local frame = Tabs.comfy_panel_get_active_frame(player)
        if not frame then
            return
        end
        if frame.name ~= module_name then
            return
        end

        local is_spamming = SpamProtection.is_spamming(player, nil, 'Admin Player Select')
        if is_spamming then
            return
        end

        local data = {player = player, frame = frame}
        create_admin_panel(data)
    end
end

Tabs.add_tab_to_gui({name = module_name, id = create_admin_panel_token, admin = true})

Event.add(defines.events.on_gui_text_changed, text_changed)
Event.add(defines.events.on_gui_click, on_gui_click)
Event.add(defines.events.on_gui_selection_state_changed, on_gui_selection_state_changed)
