require "behaviours/chaseandattack"
require "behaviours/wander"
require "behaviours/faceentity"
require "behaviours/follow"
require "behaviours/standstill"
require "behaviours/leash"
require "behaviours/panic"
require "behaviours/runaway"
require "behaviours/doaction"

local MIN_FOLLOW_DIST = 1
local MAX_FOLLOW_DIST = 9
--local TARGET_FOLLOW_DIST = (MAX_FOLLOW_DIST+MIN_FOLLOW_DIST)/2
local TARGET_FOLLOW_DIST = 2
--local GO_HOME_DIST = 1
local GO_HOME_DIST = 0

----
local MIN_FOLLOW_LEADER = 1
local MAX_FOLLOW_LEADER = 6
--local TARGET_FOLLOW_LEADER = (MAX_FOLLOW_LEADER+MIN_FOLLOW_LEADER)/2
local TARGET_FOLLOW_LEADER = 2
local LEASH_RETURN_DIST = 3.5
local LEASH_MAX_DIST = 5
----
local SEE_ENEMY_DIST = 4
----

local MAX_CHASE_TIME = 30

local TRADE_DIST = 20

local MAX_WANDER_DIST = 15

local SEE_FOOD_DIST = 15
local FIND_FOOD_HUNGER_PERCENT = 0.4 
--local MAX_WANDER_DIST = 20
--local MAX_CHASE_DIST = 30

local START_RUN_DIST = 4
local STOP_RUN_DIST = 6

local KEEP_WORKING_DIST = 15
local SEE_WORK_DIST = 20

local function HasStateTags(inst, tags)
    for k,v in pairs(tags) do
        if inst.sg:HasStateTag(v) then
            return true
        end
    end
end

local function KeepWorkingAction(inst, actiontags)
    return inst.components.follower.leader and inst.components.follower.leader:GetDistanceSqToInst(inst) <= KEEP_WORKING_DIST*KEEP_WORKING_DIST and 
    HasStateTags(inst.components.follower.leader, actiontags)
end

local function StartWorkingCondition(inst, actiontags)
    return inst.components.follower.leader and HasStateTags(inst.components.follower.leader, actiontags) and not HasStateTags(inst, actiontags)
end

local function FindObjectToWorkAction(inst, action)
    if inst.sg:HasStateTag("working") then
        return 
    end
    local target = FindEntity(inst.components.follower.leader, SEE_WORK_DIST, function(item) return item.components.workable and item.components.workable.action == action end)
    if target then
        --print(GetTime(), target)
        return BufferedAction(inst, target, action)
    end
end

local function IsHungry(inst)
    return inst.components.hunger and inst.components.hunger:GetPercent() < FIND_FOOD_HUNGER_PERCENT
end

local function IsStarving(inst)
    return inst.components.hunger and inst.components.hunger:IsStarving()

end
local function ShouldStandStill(inst)
    return inst.components.hunger and inst.components.hunger:IsStarving() and inst:HasTag("never")


end
local function CanStandStill(inst)
    return inst.components.hunger and inst.components.hunger:IsStarving() and inst:HasTag("animals") and inst:HasTag("never")
end
local function CanSeeFood(inst)
    local target = FindEntity(inst, SEE_FOOD_DIST, function(item) return inst.components.eater:CanEat(item) end)
    if target then
        --print("CanSeeFood", inst.name, target.name)
    end
    return target
end

local function FindFoodAction(inst)
    local target = CanSeeFood(inst)
    if target then
        return BufferedAction(inst, target, ACTIONS.EAT)
    end
end

local function GetTraderFn(inst)
    return (inst.components.follower.leader and inst.components.trader:IsTryingToTradeWithMe(inst.components.follower.leader)) and inst.components.follower.leader or nil
end

local function KeepTraderFn(inst, target)
    return inst.components.trader:IsTryingToTradeWithMe(target)
end

local function ShouldRunAway(inst, target)
    return inst:HasTag("animal") and not inst.components.trader:IsTryingToTradeWithMe(target)
end

local function BattleCommand(inst, target)
    return inst:HasTag("fightn") and not inst.components.trader:IsTryingToTradeWithMe(target)

end

local function BabyRunAway(inst, target)
    return inst:HasTag("level1") and not inst:HasTag("animals") and not inst.components.trader:IsTryingToTradeWithMe(target)
end

local function ShouldStopCommand(inst, target)
    return inst:HasTag("animals") 
end

local mushasmallbrain = Class(Brain, function(self, inst)
    Brain._ctor(self, inst)
end)
--------------

local function GetLeader(inst)
    return inst.components.follower ~= nil and inst.components.follower.leader or nil
end

local function GetStayPos(inst)
	return inst.components.staycommand.locations["stayspot"]
end

local function GetWanderPoint(inst)
	if inst.components.staycommand and inst.components.staycommand:IsCurrentlyStaying() then
		return GetStayPos(inst)
	else
		local target = GetLeader(inst) or GetPlayer()
   		if target then
        		return target:GetPosition()
    		end
	end
end
local function ShouldGoHome(inst)
    local homePos = inst.components.staycommand.locations["stayspot"]
    local myPos = Vector3(inst.Transform:GetWorldPosition() )

    return (homePos and distsq(homePos, myPos) > GO_HOME_DIST)
end

local function GoHomeAction(inst)
    local homePos = inst.components.staycommand.locations["stayspot"]
    if homePos then
        return BufferedAction(inst, nil, ACTIONS.GOHOME, nil, homePos, nil, 2.2)

    end
end

--------------
function mushasmallbrain:OnStart()
    local root = 
-- Panic(self.inst)),
--		

    PriorityNode({
            --[[WhileNode(function() return self.inst.components.health:GetPercent() < 0.50 end, "LowHealth", StandStill(self.inst, CanStandStill, Follow(self.inst, function() return self.inst.components.follower.leader end, 1, 2, 3 ))),]]
			
		WhileNode( function() return self.inst.components.health:GetPercent() < 0.5 and self.inst.components.combat.target == nil or not self.inst.components.combat:InCooldown() end, "AttackMomentarily", ChaseAndAttack(self.inst, 8,12)),
              WhileNode( function() return self.inst.components.combat.target and self.inst.components.combat:InCooldown() end, "Dodge",
                    RunAway(self.inst, function() return self.inst.components.combat.target and self.inst.components.health:GetPercent() < 0.5 end, 3, 7) ),
ChaseAndAttack(self.inst, 8,10),

			
        FaceEntity(self.inst, GetTraderFn, KeepTraderFn),
        -- when starving prefer finding food over fighting

        SequenceNode{
            ConditionNode(function() return IsStarving(self.inst) and CanSeeFood(self.inst) end, "SeesFoodToEat"),
            ParallelNodeAny {
                WaitNode(math.random()*.4),
                PriorityNode {
                    StandStill(self.inst, ShouldStandStill),
                    Follow(self.inst, function() return self.inst.components.follower.leader end, MIN_FOLLOW_DIST, TARGET_FOLLOW_DIST, MAX_FOLLOW_DIST),

                },
            },
            DoAction(self.inst, function() return FindFoodAction(self.inst) end),
        },
        SequenceNode{
            ConditionNode(function() return self.inst.components.health:GetPercent() > 0.2 and self.inst:HasTag("defense") and self.inst:HasTag("closea") and not self.inst:HasTag("fara") and not self.inst:HasTag("fightn") and self.inst.components.combat.target ~= nil end, "HasTarget"),
            WaitNode(math.random()*.9),
            ChaseAndAttack(self.inst, 8),
        },
--
  RunAway(self.inst, "epic", 9, 15, function(target) return ShouldStopCommand(self.inst, target) end ),
  RunAway(self.inst, "monster", 6, 12, function(target) return ShouldStopCommand(self.inst, target) end ),
  RunAway(self.inst, "insect", 6, 12, function(target) return ShouldStopCommand(self.inst, target) end ),
  RunAway(self.inst, "animal", 5, 11, function(target) return ShouldStopCommand(self.inst, target) end ),
  RunAway(self.inst, "guard", 4, 10, function(target) return ShouldStopCommand(self.inst, target) end ),

  RunAway(self.inst, "monster", 1, 1, function(target) return BattleCommand(self.inst, target) end ),
  RunAway(self.inst, "epic", 5, 5, function(target) return BattleCommand(self.inst, target) end ),
 -- RunAway(self.inst, "insect", 1, 1, function(target) return BattleCommand(self.inst, target) end ),
  RunAway(self.inst, "guard", 2, 3, function(target) return BattleCommand(self.inst, target) end ),

          RunAway(self.inst, "crazy", 4, 5),
   
              WhileNode(function() return StartWorkingCondition(self.inst, {"chopping", "prechop"}) and 
        KeepWorkingAction(self.inst, {"chopping", "prechop"}) end, "keep chopping",
            DoAction(self.inst, function() return FindObjectToWorkAction(self.inst, ACTIONS.CHOP) end)),

        WhileNode(function() return StartWorkingCondition(self.inst, {"mining", "premine"}) and 
        KeepWorkingAction(self.inst, {"mining", "premine"}) end, "keep mining",                   
            DoAction(self.inst, function() return FindObjectToWorkAction(self.inst, ACTIONS.MINE) end)),    
			
RunAway(self.inst, "player", 2, 2, function(target) return BabyRunAway(self.inst, target) end ),
			
	IfNode(function() 
		if self.inst.components.follower.leader ~= nil and self.inst.components.staycommand and self.inst.components.staycommand:IsCurrentlyStaying() == false then
				self.inst:RemoveTag("animals")
				self.inst:AddTag("defense")
				self.inst:RemoveTag("grow")
				self.inst:RemoveTag("notarget")
			return true
		elseif self.inst.components.follower.leader ~= nil and not self.inst.components.staycommand then
			return true
		end
		end, "has leader",	
		Follow(self.inst, GetLeader, MIN_FOLLOW_LEADER, TARGET_FOLLOW_LEADER, MAX_FOLLOW_LEADER),
		FaceEntity(self.inst, GetLeader, GetLeader)),

IfNode(function() 
		
		if self.inst.components.follower.leader ~= nil and self.inst.components.staycommand and self.inst.components.staycommand:IsCurrentlyStaying() == true then
				self.inst:AddTag("animals")
				self.inst:RemoveTag("defense")
				self.inst:AddTag("grow")
				self.inst:AddTag("notarget")
self.inst.components.combat:GiveUp()
			return true
		end
		end, "has leader",	
		WhileNode(function() return ShouldGoHome(self.inst) end, "ShouldGoHome",
            		DoAction(self.inst, GoHomeAction, "Go Home", true ))),  

---------
        SequenceNode{
            ConditionNode(function() return IsHungry(self.inst) and CanSeeFood(self.inst) end, "SeesFoodToEat"),
            ParallelNodeAny {
                WaitNode(1 + math.random()*2),
                PriorityNode {
                    StandStill(self.inst, ShouldStandStill),
                    Follow(self.inst, function() return self.inst.components.follower.leader end, MIN_FOLLOW_DIST, TARGET_FOLLOW_DIST, MAX_FOLLOW_DIST),

                },
            },
            DoAction(self.inst, function() return FindFoodAction(self.inst) end),
        },
        PriorityNode {
            StandStill(self.inst, ShouldStandStill),
            Follow(self.inst, function() return self.inst.components.follower.leader end, MIN_FOLLOW_DIST, TARGET_FOLLOW_DIST, MAX_FOLLOW_DIST),
        },

        Wander(self.inst, function() if self.inst.components.follower.leader then return Vector3(self.inst.components.follower.leader.Transform:GetWorldPosition()) end end, MAX_FOLLOW_DIST- 1, {minwalktime=.5, randwalktime=.5, minwaittime=6, randwaittime=3}),
    },.25)
    self.bt = BT(self.inst, root)
 end

return mushasmallbrain