dofile_once("data/scripts/lib/utilities.lua")
dofile_once("data/scripts/lib/coroutines.lua")
dofile( "mods/spellbound_bundle/files/scripts/utils.lua" )

local function WideRaytraceSurfacesAndLiquiform(x, y, x2, y2, width)
	local dx, dy = x2-x, y2-y
	local dist = math.sqrt(dx*dx + dy*dy)
	local dir_x, dir_y = dx/dist, dy/dist

	local perp_x, perp_y = -dir_y, dir_x

	local hit = false
	local hit_x, hit_y = x2, y2
	
	for dist = -(width / 2), (width / 2) do
		if(dist ~= 0)then
			local start_x, start_y = x -dir_y * dist, y + dir_x * dist
			local end_x, end_y = start_x + dx, start_y + dy
			hit, hit_x, hit_y = RaytraceSurfacesAndLiquiform(start_x, start_y, end_x, end_y)
			if(hit)then
				break
			end
		else
			hit, hit_x, hit_y = RaytraceSurfacesAndLiquiform(x, y, x2, y2)
			if(hit)then
				break
			end
		end
	end

	return hit, hit_x, hit_y
end

local function get_aim_position(shooter, ignore_raytrace)
	wide_raytrace = wide_raytrace or false
	dofile_once("data/scripts/lib/utilities.lua")
	local x, y = EntityGetTransform(shooter)
	local controls_component = EntityGetFirstComponentIncludingDisabled(shooter, "ControlsComponent")
	if(controls_component ~= nil)then
		if(EntityHasTag(shooter, "player_unit"))then
			
			local cursor_x, cursor_y = 0, 0
			if(is_using_gamepad(player))then
				cursor_x, cursor_y = ComponentGetValue2(controls_component, "mGamePadCursorInWorld")
			else
				cursor_x, cursor_y = ComponentGetValue2(controls_component, "mMousePosition")
			end

			-- get direction from shooter to cursor
			local dx, dy = cursor_x - x, cursor_y - y
			local dist = math.sqrt(dx * dx + dy * dy)
			local aim_dir_x, aim_dir_y = dx / dist, dy / dist

			local did_hit, aim_x, aim_y = false, 0, 0;
			local hit_wide = false

			if(not ignore_raytrace)then

				did_hit, aim_x, aim_y = RaytraceSurfacesAndLiquiform( x, y, x + (aim_dir_x * 120), y + (aim_dir_y * 120) )
				hit_wide = WideRaytraceSurfacesAndLiquiform( x, y, x + (aim_dir_x * 120), y + (aim_dir_y * 120), 10 )
				
				if(dist < 120)then
					did_hit, aim_x, aim_y = RaytraceSurfacesAndLiquiform( x, y, cursor_x, cursor_y )
					hit_wide = WideRaytraceSurfacesAndLiquiform( x, y, cursor_x, cursor_y, 10 )
				end
			else
				aim_x, aim_y = x + (aim_dir_x * 120), y + (aim_dir_y * 120)
				if(dist < 120)then
					aim_x, aim_y = cursor_x, cursor_y
				end
			end

			return aim_x, aim_y, did_hit, hit_wide
		else
			local aim_dir_x, aim_dir_y = ComponentGetValue2(controls_component, "mAimingVector")

			local did_hit, aim_x, aim_y = false, 0, 0
			local hit_wide = false
			if(not ignore_raytrace)then
				did_hit, aim_x, aim_y = RaytraceSurfacesAndLiquiform( x, y, x + (aim_dir_x * 120), y + (aim_dir_y * 120) )
				hit_wide = WideRaytraceSurfacesAndLiquiform( x, y, x + (aim_dir_x * 120), y + (aim_dir_y * 120), 10 )
			else
				aim_x, aim_y = x + (aim_dir_x * 120), y + (aim_dir_y * 120)
			end
			return aim_x, aim_y, did_hit, hit_wide
		end
	end
	return nil, nil
end

local card_entity = GetUpdatedEntityID()
local shooter = EntityGetRootEntity(card_entity)
local wand = EntityGetParent(card_entity)

local x, y = EntityGetTransform(shooter)
local wand_x, wand_y = EntityGetTransform(wand)
local card_x, card_y = EntityGetTransform(card_entity)

local brush_entity = EntityGetNamedChild(card_entity, "brush")
local brush_sprite = EntityGetFirstComponentIncludingDisabled(brush_entity, "SpriteComponent")


local storage = EntityGetFirstComponentIncludingDisabled(card_entity, "MaterialInventoryComponent")

local total_materials = 0

local brush_storage = EntityGetFirstComponentIncludingDisabled(brush_entity, "MaterialInventoryComponent")


local brush_count_per_material_type = ComponentGetValue2( brush_storage, "count_per_material_type");
for k,v in pairs(brush_count_per_material_type) do
	if v ~= 0 then 
		local material_name = CellFactory_GetName(k-1)
		total_materials = total_materials + v
		--AddMaterialInventoryMaterial(card_entity, material_name, v)
		--GamePrint(material_name .. ": " .. v)
	end
end

if(total_materials < 100)then
	total_materials = 0
end

local item_comp = EntityGetFirstComponentIncludingDisabled(card_entity, "ItemComponent")
if(item_comp ~= nil)then
	ComponentSetValue2( item_comp, "item_name", "Magic Pencil ("..tostring(math.floor(total_materials / 50)).."% Full)" )
	local ability_component = EntityGetFirstComponentIncludingDisabled(card_entity, "AbilityComponent")
	if(ability_component ~= nil)then
		ComponentSetValue2( ability_component, "ui_name", "Magic Pencil ("..tostring(math.floor(total_materials / 50)).."% Full)" )
	end
end

local is_drawing = false
local is_sucking = false

if(EntityHasTag(shooter, "player_unit"))then
	local controls_component = EntityGetFirstComponentIncludingDisabled(shooter, "ControlsComponent")
	is_drawing = ComponentGetValue2(controls_component, "mButtonDownFire")
	if(not is_drawing)then
		is_sucking = ComponentGetValue2(controls_component, "mButtonDownFire2")
	end
else
	local animal_ai_component = EntityGetFirstComponentIncludingDisabled(shooter, "AnimalAIComponent")
	if(animal_ai_component ~= nil)then
		local can_attack_next_frame = ComponentGetValue2(animal_ai_component, "mRangedAttackNextFrame")
		if(can_attack_next_frame)then
			if(total_materials > 10)then
				is_drawing = true
			else
				is_sucking = true
			end
		end
	end
end

local function DoesPixelExist(x, y)
	return not Raytrace(x, y - 0.1, x, y + 0.1)
end

local function DoesEntityExistWithinRadius(origin_x, origin_y, radius, tag, exclude)
	exclude = exclude or {}
	local entities = EntityGetInRadiusWithTag(origin_x, origin_y, radius, tag)
	for k, entity in ipairs(entities) do
		local allow = true
		for k, v in ipairs(exclude)do
			if(v == entity)then
				allow = false
				break
			end
		end

		if(allow)then
			return true
		end
	end

	return false
end

local function create_ray(x, y, x2, y2, direction, target)

	

	if(direction)then
		local old_x, old_y = x, y
		x, y = x2, y2
		x2, y2 = old_x, old_y
	end
	
	local dx, dy = x - x2, y - y2

	local dist = math.sqrt(dx * dx + dy * dy)
	local dir_x, dir_y = dx / dist, dy / dist

	local rand_dir_x, rand_dir_y = vec_rotate(dir_x, dir_y, math.rad(Random(-20, 20)))

	local vel_x, vel_y = rand_dir_x * (180 + Random(0,100)), rand_dir_y * (180 + Random(0,100))

	local projectile = shoot_projectile( shooter, (not direction) and "mods/spellbound_bundle/files/new_spells/magic_pen/draw_projectile.xml" or "mods/spellbound_bundle/files/new_spells/magic_pen/suck_projectile.xml", x2, y2, vel_x, vel_y )

	EntitySetVariable(projectile, "target_x", "int", x)
	EntitySetVariable(projectile, "target_y", "int", y)
	EntitySetVariable(projectile, "target", "int", target)
end

local function check_emitters(entity, x, y, ignore)
	local emitters = EntityGetComponentIncludingDisabled(brush_entity, "ParticleEmitterComponent")
	local valid_emitters = {}
	local invalid_emitters = {}
	for k, v in ipairs(emitters)do
		local emitter_offset_x, emitter_offset_y = ComponentGetValue2(v, "offset")
		local emitter_x, emitter_y = x + emitter_offset_x, y + emitter_offset_y;

		local valid_spot = DoesPixelExist(emitter_x, emitter_y);
		local no_enemy = not DoesEntityExistWithinRadius(emitter_x, emitter_y, 15, "mortal", ignore)

		if(valid_spot and no_enemy)then
			table.insert(valid_emitters, {comp = v, x = emitter_x, y = emitter_y})
		else
			table.insert(invalid_emitters, {comp = v, x = emitter_x, y = emitter_y})
		end
	end

	return valid_emitters, invalid_emitters
end

local normalize_range = function(value, min, max)
	return (value - min) / (max - min)
end

local aim_x, aim_y, did_hit, hit_suck = get_aim_position(shooter, not is_sucking)

local function EvRandom(min, max)
	min = min or 0
	max = max or 1
	min = min * 1000
	max = max * 1000
	return math.random(min, max) / 1000
end

if(aim_x ~= nil)then

	local valid_emitters, invalid_emitters = check_emitters(brush_entity, aim_x, aim_y, {shooter})

	EntitySetComponentIsEnabled(brush_entity, brush_sprite, true)
	EntitySetTransform(brush_entity, aim_x, aim_y)

	particles_spawned = particles_spawned or {}

	for i = #particles_spawned, 1, -1 do
		if(particles_spawned[i] == nil or (GameGetFrameNum() - particles_spawned[i]) > 2)then
			table.remove(particles_spawned, i)
		end
	end

	if(is_drawing)then
		if(total_materials > 100)then

			for k, v in ipairs(valid_emitters)do
				EntitySetComponentIsEnabled(brush_entity, v.comp, true)

				if(#particles_spawned == 0)then
					table.insert(particles_spawned, GameGetFrameNum())
					create_ray(aim_x, aim_y, card_x, card_y, false, brush_entity)
				end

			end

			for k, v in ipairs(invalid_emitters)do
				EntitySetComponentIsEnabled(brush_entity, v.comp, false)
			end
		end
	elseif(is_sucking)then
		if(total_materials < 2000 and hit_suck)then
			local suckers = EntityGetComponentIncludingDisabled(brush_entity, "MaterialSuckerComponent")
			for k, v in ipairs(suckers)do
				EntitySetComponentIsEnabled(brush_entity, v, true)
			end

			for k, v in ipairs(invalid_emitters)do

				if(#particles_spawned == 0)then
					table.insert(particles_spawned, GameGetFrameNum())
					create_ray(v.x, v.y, card_x, card_y, true, card_entity)
				end
			end
		else
			local suckers = EntityGetComponentIncludingDisabled(brush_entity, "MaterialSuckerComponent") 
			for k, v in ipairs(suckers)do
				EntitySetComponentIsEnabled(brush_entity, v, false)
			end
		end
	end

	if(not is_sucking)then
		local suckers = EntityGetComponentIncludingDisabled(brush_entity, "MaterialSuckerComponent") 
		for k, v in ipairs(suckers)do
			EntitySetComponentIsEnabled(brush_entity, v, false)
		end
	end

	if(not is_drawing)then
		local emitters = EntityGetComponentIncludingDisabled(brush_entity, "ParticleEmitterComponent")
		for k, v in ipairs(emitters)do
			EntitySetComponentIsEnabled(brush_entity, v, false)
		end
	end

else
	local suckers = EntityGetComponentIncludingDisabled(brush_entity, "MaterialSuckerComponent") 
	for k, v in ipairs(suckers)do
		EntitySetComponentIsEnabled(brush_entity, v, false)
	end
	local emitters = EntityGetComponentIncludingDisabled(brush_entity, "ParticleEmitterComponent")
	for k, v in ipairs(emitters)do
		EntitySetComponentIsEnabled(brush_entity, v, true)
	end
	EntitySetComponentIsEnabled(brush_entity, brush_sprite, false)
end