---@diagnostic disable: inject-field
-- This file is part of thesixthroc's Pirate Ship softmod, licensed under GPLv3 and stored at https://github.com/ComfyFactory/ComfyFactorio and https://github.com/danielmartin0/ComfyFactorio-Pirates.

local Memory = require('maps.pirates.memory')
local Common = require('maps.pirates.common')
local Classes = require('maps.pirates.roles.classes')
local GuiCommon = require('maps.pirates.gui.common')
local Public = {}

local _inspect = require('utils.inspect').inspect

local window_name = 'classes'

local widths = {}
widths['available_classes'] = 150
widths['taken_by'] = 150
widths['action_buttons'] = 100

local function add_class_entry(player, class, taken_by_player_index, index)
	if not player.gui.screen[window_name .. '_piratewindow'] then
		return
	end
	local flow
	flow = player.gui.screen[window_name .. '_piratewindow']

	local class_list_panel_table = flow.scroll_pane.class_list_panel_table

	-- Class label
	local explanation = Classes.explanation(class, false)
	local full_explanation

	if Classes.class_purchase_requirement[class] then
		full_explanation = {
			'pirates.class_explanation_upgraded_class',
			Classes.display_form(class),
			Classes.display_form(Classes.class_purchase_requirement[class]),
			explanation,
		}
	else
		full_explanation = { 'pirates.class_explanation', Classes.display_form(class), explanation }
	end

	local available_class_label = class_list_panel_table.add({
		type = 'label',
		caption = Classes.display_form(class),
		tooltip = full_explanation,
	})
	available_class_label.style.minimal_width = widths['available_classes']
	available_class_label.style.maximal_width = widths['available_classes']

	-- Player label
	local taken_by_player_name = taken_by_player_index and game.players[taken_by_player_index].name or ''
	local taken_by_label = class_list_panel_table.add({
		name = 'player_label' .. index,
		type = 'label',
		caption = taken_by_player_name,
	})
	taken_by_label.style.minimal_width = widths['taken_by']
	taken_by_label.style.maximal_width = widths['taken_by']

	-- Button
	local button

	if not taken_by_player_index then
		button = class_list_panel_table.add({
			name = 'button' .. index,
			type = 'button',
			caption = { 'pirates.gui_classes_take' },
			tooltip = { 'pirates.gui_classes_take_enabled_tooltip' },
		})
	elseif taken_by_player_index == player.index then
		button = class_list_panel_table.add({
			name = 'button' .. index,
			type = 'button',
			caption = { 'pirates.gui_classes_drop' },
			tooltip = { 'pirates.gui_classes_drop_tooltip' },
		})
		button.style.font_color = { r = 1, g = 0, b = 0 }
		button.style.hovered_font_color = { r = 1, g = 0, b = 0 }
		button.style.clicked_font_color = { r = 1, g = 0, b = 0 }
	else
		button = class_list_panel_table.add({
			name = 'button' .. index,
			type = 'button',
			enabled = false, -- wanted to make "visble = false" instead, but table doesn't like that
			caption = { 'pirates.gui_classes_take' },
			tooltip = { 'pirates.gui_classes_take_disabled_tooltip' },
		})
	end
	button.tags = { type = 'pirates_' .. window_name, index = index }

	button.style.minimal_width = widths['action_buttons']
	button.style.maximal_width = widths['action_buttons']
end

function Public.toggle_window(player)
	local memory = Memory.get_crew_memory()
	local flow, flow2, flow3

	--*** OVERALL FLOW ***--
	if player.gui.screen[window_name .. '_piratewindow'] then
		player.gui.screen[window_name .. '_piratewindow'].destroy()
		return
	end

	if not Common.is_id_valid(memory.id) then
		return
	end

	flow = GuiCommon.new_window(player, window_name)
	flow.caption = { 'pirates.gui_classes' }

	-- Set the window position
	local gui_memory = Memory.get_global_memory().player_gui_memories[player.index]
	if gui_memory and gui_memory[window_name] and gui_memory[window_name].position then
		flow.location = gui_memory[window_name].position
	else
		flow.location = GuiCommon.default_window_positions[window_name] or { x = 300, y = 76 }
	end

	flow.style.maximal_width = 500

	flow2 = flow.add({
		name = 'headers',
		type = 'flow',
		direction = 'horizontal',
	})

	flow3 = flow2.add({
		name = 'available_classes',
		type = 'label',
		caption = { 'pirates.gui_classes_available_classes' },
	})
	flow3.style.minimal_width = widths['available_classes']
	flow3.style.maximal_width = widths['available_classes']
	flow3.style.font = 'heading-2'
	flow3.style.font_color = GuiCommon.section_header_font_color

	flow3 = flow2.add({
		name = 'taken_by',
		type = 'label',
		caption = { 'pirates.gui_classes_taken_by' },
	})
	flow3.style.minimal_width = widths['taken_by']
	flow3.style.maximal_width = widths['taken_by']
	flow3.style.font = 'heading-2'
	flow3.style.font_color = GuiCommon.section_header_font_color

	flow3 = flow2.add({
		name = 'action_buttons',
		type = 'label',
		caption = { 'pirates.gui_classes_actions' },
	})
	flow3.style.minimal_width = widths['action_buttons']
	flow3.style.maximal_width = widths['action_buttons']
	flow3.style.font = 'heading-2'
	flow3.style.font_color = GuiCommon.section_header_font_color

	-- List management
	local scroll_pane = flow.add({
		type = 'scroll-pane',
		name = 'scroll_pane',
		direction = 'vertical',
		horizontal_scroll_policy = 'never',
		vertical_scroll_policy = 'auto',
	})
	scroll_pane.style.maximal_height = 500
	scroll_pane.style.bottom_margin = 10

	scroll_pane.add({
		type = 'table',
		name = 'class_list_panel_table',
		column_count = 3,
	})

	for i, class_entry in ipairs(memory.unlocked_classes) do
		add_class_entry(player, class_entry.class, class_entry.taken_by, i)
	end

	memory.class_entry_count = #memory.unlocked_classes

	GuiCommon.flow_add_close_button(flow, window_name .. '_piratebutton')
end

function Public.full_update(player, force_refresh)
	force_refresh = force_refresh or nil
	-- close and open the window to reconstruct the window (not really necessary when window is closed, but doesn't really matter as it should be ran once and only when necessary)
	if force_refresh then
		Public.toggle_window(player)
		Public.toggle_window(player)
	end

	if not player.gui.screen[window_name .. '_piratewindow'] then
		return
	end
	local flow = player.gui.screen[window_name .. '_piratewindow']

	local memory = Memory.get_crew_memory()

	--*** Overwrite contents ***--

	local class_list_panel_table = flow.scroll_pane.class_list_panel_table

	-- Currently assuming class list size never decreases

	-- Update current content table
	for i = 1, memory.class_entry_count do
		local label = class_list_panel_table['player_label' .. i]
		if label then
			local class_entry = memory.unlocked_classes[i]
			label.caption = class_entry.taken_by and game.players[class_entry.taken_by].name or ''

			local black = { r = 0, g = 0, b = 0 }
			local red = { r = 1, g = 0, b = 0 }

			local button = class_list_panel_table['button' .. i]
			if not class_entry.taken_by then
				button.caption = { 'pirates.gui_classes_take' }
				button.tooltip = { 'pirates.gui_classes_take_enabled_tooltip' }
				button.style.font_color = black
				button.style.hovered_font_color = black
				button.style.clicked_font_color = black
				button.enabled = true
			elseif class_entry.taken_by == player.index then
				button.caption = { 'pirates.gui_classes_drop' }
				button.tooltip = { 'pirates.gui_classes_drop_tooltip' }
				button.style.font_color = red
				button.style.hovered_font_color = red
				button.style.clicked_font_color = red
				button.enabled = true
			else
				button.caption = { 'pirates.gui_classes_take' }
				button.tooltip = { 'pirates.gui_classes_take_disabled_tooltip' }
				button.style.font_color = black
				button.style.hovered_font_color = black
				button.style.clicked_font_color = black
				button.enabled = false
			end
		else
			log('Error: Non-existant label index, here some debug info.')
			log(_inspect(class_list_panel_table))
			log(memory.class_entry_count)
			log(memory.unlocked_classes)
		end
	end

	-- If new entries were added since last update, add them to GUI
	if memory.class_entry_count ~= #memory.unlocked_classes then
		for i = memory.class_entry_count + 1, #memory.unlocked_classes do
			local class_entry = memory.unlocked_classes[i]
			add_class_entry(player, class_entry.class, class_entry.taken_by, i)
		end

		memory.class_entry_count = #memory.unlocked_classes
	end
end

function Public.click(event)
	if not event.element then
		return
	end
	if not event.element.valid then
		return
	end

	local player = game.players[event.element.player_index]
	if not player.gui.screen[window_name .. '_piratewindow'] then
		return
	end

	local tags = event.element.tags
	if not tags then
		return
	end
	if tags.type ~= 'pirates_' .. window_name then
		return
	end

	local memory = Memory.get_crew_memory()

	if tags.index then
		local button_is_take_class = (not memory.unlocked_classes[tags.index].taken_by) and true or false

		if button_is_take_class then
			local class_to_assign = memory.unlocked_classes[tags.index].class
			Classes.assign_class(player.index, class_to_assign, tags.index)
			return
		else -- button is drop class
			Classes.assign_class(player.index, nil, tags.index)
			return
		end
	end
end

return Public
