-- local brain = require "brains/wonkyskeleton"

local assets =
{
    Asset("ANIM", "anim/wonkyskeleton.zip"),
	
	Asset("ANIM", "anim/swap_wsclothe.zip"),
}

local prefabs =
{
	"boneshard",
	"ash",
	"goldnugget",
	"lantern",
}

SetSharedLootTable( 'wskeleton',
{
    {'boneshard', 1.000},
    {'boneshard',  0.250},
    {'boneshard',  0.070},
	{'ash',  0.700},
	{'goldnugget',  0.200},
	{'lantern',  0.050},	
})

local ribcage_cloth_list = {
	"",
	"swap_regularwsshirt",
	"swap_summerwsshirt",
	"swap_winterwsclothe",
	"swap_wolfgangwsclothe",
}

local function NightRetarget(inst)
    local targetDist = TUNING.SPIDER_TARGET_DIST
    if inst.components.knownlocations:GetLocation("investigate") then
        targetDist = TUNING.SPIDER_INVESTIGATETARGET_DIST
    end
    return FindEntity(inst, targetDist, 
						function(guy) 
							return inst.components.combat:CanTarget(guy)
								and not (inst.components.follower and inst.components.follower.leader == guy)
						end,
						{ "character" },
						{"monster"}
    )
end

local function keeptargetfn(inst, target)
   return target
          and target.components.combat
          and target.components.health
          and not target.components.health:IsDead()
          and not (inst.components.follower and inst.components.follower.leader == target)
          and not (inst.components.follower and inst.components.follower:IsLeaderSame(target))
end

local function OnAttacked(inst, data)
	if inst.components.follower and inst.leaderID then
		if data.attacker.userid and data.attacker.userid == inst.leaderID then
			if inst.rememberleaderloc then
				inst.rememberleaderloc:Cancel()
				inst.rememberleaderloc = nil
			end
			inst.leaderID = nil
		else
			inst.components.combat:SetTarget(data.attacker)
		end
	else
		inst.components.combat:SetTarget(data.attacker)
	end
end

local function OnIsDay(inst, phase)
    if phase == "night" or phase == "dusk" then
		if inst.components.follower and inst.components.follower.leader then
			if math.random() < 0.85 then
				inst.components.follower.targettime = GetTime() + TUNING.TOTAL_DAY_TIME
			else
				inst.components.follower:StopFollowing()
			end
		elseif inst.components.follower and inst.leaderID then
			if math.random() > 0.85 then
				inst.leaderID = nil
				if inst.waitforleader then
					inst.waitforleader:Cancel()
					inst.waitforleader = nil
				end
			end		
		end
		
		if inst.components.follower and inst.leaderID == nil then
			inst.components.combat:SetRetargetFunction(1, NightRetarget)
		end
    else
	    inst.components.combat.targetfn = nil
		inst.components.combat.retargetperiod = nil
		
		if inst.components.combat.retargettask then
			inst.components.combat.retargettask:Cancel()
			inst.components.combat.retargettask = nil
		end
    end
end

local function CalcSanityAura(inst, observer)
    return inst.components.sanityaura.aura
end

local function MakeWSWeapon(inst)
    if inst.components.inventory then
        local boneproj = CreateEntity()
        --[[Non-networked entity]]
        boneproj.entity:AddTransform()
        boneproj:AddComponent("weapon")
        boneproj.components.weapon:SetDamage(15)
        boneproj.components.weapon:SetRange(8, 10)
        boneproj.components.weapon:SetProjectile("wsboneproj")
		boneproj.components.weapon:SetOnAttack(function(proj, attacker, target)
													attacker.nextranged = GetTime() + attacker.rangeCD
													inst.projininv = inst.projininv - 1
													if inst.replenishproj == nil then
														inst.replenishtask = inst:DoPeriodicTask(inst.rangeCD*3, function()
																										inst.projininv = inst.projininv + 1
																										if inst.projininv == 5 then
																											inst.replenishtask:Cancel()
																											inst.replenishtask = nil
																										end
																									end
														)
													end
												end
		)
        boneproj:AddComponent("inventoryitem")
        boneproj.persists = false
        boneproj.components.inventoryitem:SetOnDroppedFn(inst.Remove)
        boneproj:AddComponent("equippable")
        
        inst.components.inventory:Equip(boneproj)
    end
end

local function ShouldAcceptItem(inst, item, giver)
	local undeadfollower = 0
	
	-- print(giver ," tries to befriend a skeleton. He already has as followers ")
    for k,v in pairs(giver.components.leader.followers) do
        if k:HasTag("mnzundeads") then
			-- print(k, " / ", v)
            undeadfollower = undeadfollower + 1
        end
    end
	
    return item.prefab == ("reviver") and undeadfollower < 3
end

local function OnGetItemFromPlayer(inst, giver, item)
	-- print("WonkySkeleton recieved item from ", giver)
    if item.prefab == ("reviver") then  
        local playedfriendsfx = false
        if inst.components.combat.target == giver then
            inst.components.combat:SetTarget(nil)
        elseif giver.components.leader ~= nil and inst.components.follower ~= nil then
            inst.SoundEmitter:PlaySound("dontstarve/common/makeFriend")
            playedfriendsfx = true
            giver.components.leader:AddFollower(inst)
            inst.components.follower:AddLoyaltyTime(TUNING.TOTAL_DAY_TIME)
			inst.leaderID = giver.userid
			inst.rememberleaderloc = inst:DoPeriodicTask(10, function() 
																if inst.components.follower.leader then
																	inst.components.knownlocations:RememberLocation("lastleaderloc", inst.components.follower.leader:GetPosition()) 
																end
															end
			)
			-- print("The Skeleton should now follow ", giver, "(Time remaining : ", inst.components.follower.targettime - GetTime(),")")
        end
    end
end

local function OnLoseLoyalty(inst)
	-- print(inst, " lost loyalty toward his leader")

	if inst.leaderID then
		inst.leaderID = nil
	end
	
	if inst.rememberleaderloc then
		inst.rememberleaderloc:Cancel()
		inst.rememberleaderloc = nil
	end
end

local function OnStopFollowing(inst, data)
	-- print(inst, "stopped following his leader ", data.leader)
	inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "following")
	inst.components.combat:SetDefaultDamage(TUNING.SPIDER_DAMAGE*3)
end

local function OnStartFollowing(inst, data)
	-- print(inst, "started following his leader ", data.leader)
	inst.components.locomotor:SetExternalSpeedMultiplier(inst, "following", 4)
	inst.components.combat:SetDefaultDamage(TUNING.SPIDER_DAMAGE*1.5)
end

local function OnSaveWS(inst, data)
	if inst.shirt ~= nil then
		data.shirt = inst.shirt
	end
	
	if inst.leaderID then
		data.leaderID = inst.leaderID
	end
end

local function OnLoadWS(inst, data)
	if data.shirt ~= nil then
		inst.shirt = data.shirt
		inst.AnimState:OverrideSymbol("swap_ribcage", "swap_wsclothe", inst.shirt)
	end
	
	if data.leaderID then
		-- print("leaderID for ", inst, " is not nil -> ", data.leaderID)
		inst.leaderID = data.leaderID
		
		inst.components.combat.targetfn = nil
		inst.components.combat.retargetperiod = nil
		
		if inst.components.combat.retargettask then
			inst.components.combat.retargettask:Cancel()
			inst.components.combat.retargettask = nil
		end
		
		if inst.waitforleader == nil then
			inst.waitforleader = inst:DoPeriodicTask(5, function()
															-- print(inst, " is checking for his leader")
															local awaitedleaded = FindEntity(inst, 20, function(guy, inst) return guy.userid and guy.userid == inst.leaderID end, { "player" } )
															if awaitedleaded and awaitedleaded.components.leader then
																awaitedleaded.components.leader:AddFollower(inst)
																inst.components.follower:AddLoyaltyTime(TUNING.TOTAL_DAY_TIME)
															
																inst.waitforleader:Cancel()
																inst.waitforleader = nil
															end
														end
			)
		end
	end
end

local normalbrain = require "brains/wonkyskeletonbrain"

local function wonkyskeletonfn()
    local inst = CreateEntity()
    
    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddLightWatcher()
    inst.entity:AddDynamicShadow()
    inst.entity:AddNetwork()

    MakeCharacterPhysics(inst, 10, .5)

    inst.DynamicShadow:SetSize(1.5, .5)
    inst.Transform:SetFourFaced()

    inst:AddTag("monster")
    inst:AddTag("hostile")
    inst:AddTag("scarytoprey")
    inst:AddTag("mnzundeads")
    inst:AddTag("trader")

    inst.AnimState:SetBank("wonkyskeleton")
    inst.AnimState:SetBuild("wonkyskeleton")
    inst.AnimState:PlayAnimation("idle", true)
	local random_shirt = GetRandomItem(ribcage_cloth_list)
	inst.AnimState:OverrideSymbol("swap_ribcage", "swap_wsclothe", random_shirt)

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

    ----------
	
	inst:AddComponent("inventory")
	
    -- inst.OnEntitySleep = OnEntitySleep

    -- locomotor must be constructed before the stategraph!
    inst:AddComponent("locomotor")
    inst.components.locomotor:SetTriggersCreep(true)
    inst.components.locomotor.pathcaps = { ignorecreep = false }
    inst.components.locomotor.walkspeed = TUNING.SPIDER_WALK_SPEED*0.2
    inst.components.locomotor.runspeed = TUNING.SPIDER_RUN_SPEED*0.2

    inst:SetStateGraph("SGwonkyskeleton")

    inst:AddComponent("lootdropper")
    inst.components.lootdropper:SetChanceLootTable('wskeleton')
	inst:DoTaskInTime(2, function()
							if random_shirt == "swap_summerwsshirt" then
								inst.components.lootdropper:AddRandomLoot("hawaiianshirt", 0.02)
							end
						end	
	)

    ---------------------     
	
    MakeMediumFreezableCharacter(inst, "body")
	
    ---------------------       

    inst:AddComponent("health")
	inst.components.health:SetMaxHealth(TUNING.SPIDER_HEALTH*2.25)
		
    inst:AddComponent("combat")
    inst.components.combat.hiteffectsymbol = "body"
    inst.components.combat:SetKeepTargetFunction(keeptargetfn)
	
    inst.components.combat:SetDefaultDamage(TUNING.SPIDER_DAMAGE*3)
    inst.components.combat:SetAttackPeriod(TUNING.SPIDER_ATTACK_PERIOD/2)
	inst.GetNewWSWeapon = MakeWSWeapon
	inst.weapon = inst:GetNewWSWeapon()
	inst.projininv = 5
	inst.rangeCD = 5
	inst.nextranged = GetTime()
	if TheWorld.state.phase == "night" or TheWorld.state.phase == "dusk" then
		inst.components.combat:SetRetargetFunction(1, NightRetarget)
	end

	inst.shirt = random_shirt
	
	inst:AddComponent("trader")
    inst.components.trader:SetAcceptTest(ShouldAcceptItem)
    inst.components.trader.onaccept = OnGetItemFromPlayer
	
    inst:AddComponent("follower")
    inst.components.follower.maxfollowtime = 2*TUNING.TOTAL_DAY_TIME
	
    ------------------

    inst:AddComponent("knownlocations")
	inst:AddComponent("homeseeker")
	inst:DoTaskInTime(2, function()
							if not inst.components.knownlocations:GetLocation("home") then
								-- print("no home found, trying to leach ", inst)
								
								local MMspawner = FindEntity(inst, 25, nil, { "MnZmachines" , "structure" , "mining" })
								if MMspawner ~= nil then
									-- print("Home found for ", inst, " ! -> ", MMspawner)
									inst.components.homeseeker:SetHome(MMspawner)
									inst.components.knownlocations:RememberLocation("home", MMspawner:GetPosition())
								end
							else
								-- print(inst, " already has a home : ", inst.components.knownlocations:GetLocation("home"))
								inst.components.homeseeker:SetHome(inst.components.knownlocations:GetLocation("home"))
							end
						end
	)

    ------------------

    inst:AddComponent("inspectable")

    ------------------

    inst:AddComponent("sanityaura")
    inst.components.sanityaura.aurafn = CalcSanityAura
    inst.components.sanityaura.aura = -TUNING.SANITYAURA_SMALL

    MakeHauntablePanic(inst)

    inst:SetBrain(normalbrain)

    inst:ListenForEvent("attacked", OnAttacked)
	inst:ListenForEvent("loseloyalty", OnLoseLoyalty)
	inst:ListenForEvent("stopfollowing", OnStopFollowing)
	inst:ListenForEvent("startfollowing", OnStartFollowing)

    inst:WatchWorldState("phase", OnIsDay)
	
	inst.OnSave = OnSaveWS
	inst.OnLoad = OnLoadWS

    return inst
end

local function onhit(inst, attacker, target)
	inst:Remove()
end

local function onthrown(inst, data)
    inst.AnimState:SetOrientation( ANIM_ORIENTATION.OnGround )
end

local function bonethrown(inst)
    inst.AnimState:PlayAnimation("thrown", true)
    inst:AddTag("NOCLICK")
    inst.persists = false
end

local function wsboneprojfn()
	local inst = CreateEntity()

	inst.entity:AddTransform()
	inst.entity:AddAnimState()
    inst.entity:AddNetwork()

    MakeInventoryPhysics(inst)

    inst.AnimState:SetBank("bone_proj")
    inst.AnimState:SetBuild("wonkyskeleton")
    inst.AnimState:PlayAnimation("thrown")

    inst:AddTag("projectile")
	inst:AddTag("blunt")

    RemovePhysicsColliders(inst)

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

	inst:AddComponent("inventoryitem")
	
    inst:AddComponent("weapon")
    inst.components.weapon:SetDamage(15)
    inst.components.weapon:SetRange(10, 12)

    inst:AddComponent("projectile")
    inst.components.projectile:SetSpeed(40)
    inst.components.projectile:SetOnHitFn(onhit)
	inst.components.projectile:SetOnThrownFn(bonethrown)
    inst:ListenForEvent("onthrown", onthrown)
    -------

    MakeHauntableLaunch(inst)

    return inst
end

return Prefab("graveyard/monsters/wonkyskeleton", wonkyskeletonfn, assets, prefabs),
		Prefab("projectiles/wsboneproj", wsboneprojfn, assets, prefabs)
