local TheNet = GLOBAL.TheNet
local require = GLOBAL.require
local TUNING = GLOBAL.TUNING
------------------------------------项圈 && HUD------------------------
local UpvalueHacker = require("tools/upvaluehacker")
local writeables = require("writeables")
local kinds = UpvalueHacker.GetUpvalue(writeables.makescreen, "kinds")
local mylanguage = GetModConfigData("language")
local beefalo_names = {
	"Fluffy McFlufferton",
	"Boof",
	"Bobby",
	"Scruffy",
	"Harry",
	"Beefchilles",
	"MEATSACK",
	"Floof",
	"Fuzzball",
	"Fluffball",
	"Nibbles",
	"Bloodhoof",
	"Sillyhorns",
	"Bicorn",
	"Salty",
	"Dusty",
	"Bubs",
	"Buck",
	"Beefalonius Maximus",
}
local myprompt = "What do you want to call your beefalo?"
local mycancel = "Cancel"
local mymiddle = "Random"
local myaccept = "Name it!"
if mylanguage == 2 then
	beefalo_names = {
	"滑稽",
	"喜大普奔",
	"天涯",
	"海角",
	"编名字好累",
	"牛排",
	"肉块",
	"凑数的",
	"胖球",
	"看飞碟",
	"德玛西亚",
	"血蹄",
	"刚角",
	"里脊肉",
	"椒盐烤肉",
	"酒香坛肉",
	"宫保鸡丁",
	"宝马",
	"鱼香肉丝",
	}
	myprompt = "想给你的牛起个什么名?"
	mycancel = "取消"
	mymiddle = "随机"
	myaccept = "命名"
end
kinds.beefalo = {
    prompt = myprompt,
    animbank = "ui_board_5x3",
    animbuild = "ui_board_5x3",
    menuoffset = GLOBAL.Vector3(6, -70, 0),

    cancelbtn = { text = mycancel, cb = nil, control = GLOBAL.CONTROL_CANCEL },
    middlebtn = { text = mymiddle, cb = function(inst, doer, widget)
            widget:OverrideText( beefalo_names[math.random(#beefalo_names)] )
        end, control = GLOBAL.CONTROL_MENU_MISC_2 },
    acceptbtn = { text = myaccept, cb = nil, control = GLOBAL.CONTROL_ACCEPT },
}

local ELEMENTBEEFALO = GLOBAL.KnownModIndex:IsModEnabled("workshop-800155159")
	for _, moddir in ipairs(GLOBAL.KnownModIndex:GetModsToLoad()) do
		if moddir == "workshop-800155159" then
			ELEMENTBEEFALO = true
		end
	end
if ELEMENTBEEFALO then
	kinds.firebeefalo = {
	    prompt = myprompt,
	    animbank = "ui_board_5x3",
	    animbuild = "ui_board_5x3",
	    menuoffset = GLOBAL.Vector3(6, -70, 0),

	    cancelbtn = { text = mycancel, cb = nil, control = GLOBAL.CONTROL_CANCEL },
	    middlebtn = { text = mymiddle, cb = function(inst, doer, widget)
	            widget:OverrideText( beefalo_names[math.random(#beefalo_names)] )
	        end, control = GLOBAL.CONTROL_MENU_MISC_2 },
	    acceptbtn = { text = myaccept, cb = nil, control = GLOBAL.CONTROL_ACCEPT },
	}
	kinds.icebeefalo = {
	    prompt = myprompt,
	    animbank = "ui_board_5x3",
	    animbuild = "ui_board_5x3",
	    menuoffset = GLOBAL.Vector3(6, -70, 0),

	    cancelbtn = { text = mycancel, cb = nil, control = GLOBAL.CONTROL_CANCEL },
	    middlebtn = { text = mymiddle, cb = function(inst, doer, widget)
	            widget:OverrideText( beefalo_names[math.random(#beefalo_names)] )
	        end, control = GLOBAL.CONTROL_MENU_MISC_2 },
	    acceptbtn = { text = myaccept, cb = nil, control = GLOBAL.CONTROL_ACCEPT },
	}
	kinds.lightningbeefalo = {
	    prompt = myprompt,
	    animbank = "ui_board_5x3",
	    animbuild = "ui_board_5x3",
	    menuoffset = GLOBAL.Vector3(6, -70, 0),

	    cancelbtn = { text = mycancel, cb = nil, control = GLOBAL.CONTROL_CANCEL },
	    middlebtn = { text = mymiddle, cb = function(inst, doer, widget)
	            widget:OverrideText( beefalo_names[math.random(#beefalo_names)] )
	        end, control = GLOBAL.CONTROL_MENU_MISC_2 },
	    acceptbtn = { text = myaccept, cb = nil, control = GLOBAL.CONTROL_ACCEPT },
	}
	kinds.beefaloking = {
	    prompt = myprompt,
	    animbank = "ui_board_5x3",
	    animbuild = "ui_board_5x3",
	    menuoffset = GLOBAL.Vector3(6, -70, 0),

	    cancelbtn = { text = mycancel, cb = nil, control = GLOBAL.CONTROL_CANCEL },
	    middlebtn = { text = mymiddle, cb = function(inst, doer, widget)
	            widget:OverrideText( beefalo_names[math.random(#beefalo_names)] )
	        end, control = GLOBAL.CONTROL_MENU_MISC_2 },
	    acceptbtn = { text = myaccept, cb = nil, control = GLOBAL.CONTROL_ACCEPT },
	}
end

AddRecipe("beefalocollar",
		{Ingredient("silk", 8),
		 Ingredient("moonrocknugget", 2),
		 Ingredient("pigskin", 2)},
		GLOBAL.RECIPETABS.TOOLS,
		GLOBAL.TECH.SCIENCE_TWO,
		nil,
		nil,
		nil,
		nil,
		nil,
		"images/inventoryimages/beefalocollar.xml")
if mylanguage == 1 then
	GLOBAL.STRINGS.CHARACTERS.WX78.DESCRIBE.BEEFALOCOLLAR = "THE MEATBAG WILL BE MY SLAVE FOREVER"
	GLOBAL.STRINGS.CHARACTERS.WATHGRITHR.DESCRIBE.BEEFALOCOLLAR = "A talisman to bind the beast's soul."
	GLOBAL.STRINGS.CHARACTERS.WOLFGANG.DESCRIBE.BEEFALOCOLLAR = "This puts name on hair-cow."
	GLOBAL.STRINGS.CHARACTERS.WAXWELL.DESCRIBE.BEEFALOCOLLAR = "This won't make it any less stupid, but it will make it mine."
	GLOBAL.STRINGS.CHARACTERS.WENDY.DESCRIBE.BEEFALOCOLLAR = "This will bind the beast to me, as Abigail's flower binds her."
	GLOBAL.STRINGS.CHARACTERS.WEBBER.DESCRIBE.BEEFALOCOLLAR = "Does this mean we'll have it all to ourselves?"
	GLOBAL.STRINGS.CHARACTERS.WICKERBOTTOM.DESCRIBE.BEEFALOCOLLAR = "This seems like more than a mere collar."
	GLOBAL.STRINGS.CHARACTERS.WOODIE.DESCRIBE.BEEFALOCOLLAR = "A beefalo to call my own, eh?"
	GLOBAL.STRINGS.CHARACTERS.WILLOW.DESCRIBE.BEEFALOCOLLAR = "This might keep its fire going longer."
end
local ismastersim = TheNet:GetIsServer()

local function OnMounted(parent, data)
	if not data.target then return end
	parent.player_classified.mountwidgetvisible:set(true)
	parent:ListenForEvent("healthdelta", parent.player_classified._OnMountHealthDelta, data.target)
	parent:ListenForEvent("hungerdelta", parent.player_classified._OnMountHungerDelta, data.target)
	parent.player_classified.mountmaxhealth:set(data.target.components.health.maxhealth)
	parent.player_classified.mounthealth:set(data.target.components.health.currenthealth)
	parent.player_classified.mountmaxhunger:set(data.target.components.hunger.max)
end

local function OnDismounted(parent, data)
	parent.player_classified.mountwidgetvisible:set(false)
	parent:RemoveEventCallback("healthdelta", parent.player_classified._OnMountHealthDelta, data.target)
	parent:RemoveEventCallback("hungerdelta", parent.player_classified._OnMountHungerDelta, data.target)
end

local function MountWidgetVisibleDirty(inst)
	if inst.mountwidgetvisible:value() then
		inst._parent.HUD:OpenBeefalo()
	else
		inst._parent.HUD:CloseBeefalo()
	end
end

local function RegisterNetListeners(inst)
	inst._parent = inst._parent or inst.entity:GetParent()
	if ismastersim then
		inst:ListenForEvent("mounted", OnMounted, inst._parent)
		inst:ListenForEvent("dismounted", OnDismounted, inst._parent)
		--I don't think this occurs, but it shouldn't hurt
		if inst._parent.components.rider.mount then
			OnMounted(inst._parent, {target = inst._parent.components.rider.mount})
		end
	end
	if GLOBAL.ThePlayer and GLOBAL.ThePlayer.player_classified == inst then
		inst:ListenForEvent("mountwidgetvisibledirty", MountWidgetVisibleDirty)
		MountWidgetVisibleDirty(inst)
	end
end

AddPrefabPostInit("player_classified", function(inst)
	inst.mounthealth = GLOBAL.net_ushortint(inst.GUID, "mount.health", "mounthealthdirty")
	inst.mountmaxhealth = GLOBAL.net_ushortint(inst.GUID, "mount.maxhealth", "mountmaxhealthdirty")
	inst.mounthunger = GLOBAL.net_ushortint(inst.GUID, "mount.hunger", "mounthungerdirty")
	inst.mountmaxhunger = GLOBAL.net_ushortint(inst.GUID, "mount.maxhunger", "mountmaxhungerdirty")
	inst.mountwidgetvisible = GLOBAL.net_bool(inst.GUID, "mount.widgetvisible", "mountwidgetvisibledirty")
	
	--Set the most likely values for the pristine state
	inst.mounthealth:set(TUNING.BEEFALO_HEALTH)
	inst.mountmaxhealth:set(TUNING.BEEFALO_HEALTH)
	-- inst.mounthunger:set(TUNING.BEEFALO_HUNGER) --most likely is zero, lol
	inst.mountmaxhunger:set(TUNING.BEEFALO_HUNGER)
	inst.mountwidgetvisible:set(false)
	
	inst._OnMountHealthDelta = function(mount, data)
		inst.mounthealth:set(mount.components.health.currenthealth)
	end
	inst._OnMountHungerDelta = function(mount, data)
		inst.mounthunger:set(mount.components.hunger.current)
	end
	
	inst:DoTaskInTime(0, RegisterNetListeners)
end)

local BeefaloWidget = require("widgets/beefalowidget")
local PlayerHud = require("screens/playerhud")
function PlayerHud:OpenBeefalo()
	if not self.beefalowidget then
		self.controls.inv.beefalowidget = self.controls.inv.root:AddChild(BeefaloWidget(self.owner))
		self.beefalowidget = self.controls.inv.beefalowidget
		self.beefalowidget:SetScale(1)
		self.beefalowidget:MoveToBack()
		self.controls.inv:Rebuild()
	end
	
	self.beefalowidget:Open()
end
function PlayerHud:CloseBeefalo()
	if self.beefalowidget then
		self.beefalowidget:Close()
	end
end

local Inv = require("widgets/inventorybar")
local _Rebuild = Inv.Rebuild
function Inv:Rebuild(...)
	_Rebuild(self, ...)
	if self.owner.HUD.beefalowidget then
		self.owner.HUD.beefalowidget.bump_for_controller = self.controller_build 
													   and self.owner.replica.inventory:GetOverflowContainer() 
													   and self.owner.HUD.beefalowidget
		self.owner.HUD.beefalowidget:UpdatePosition()
	end
end

GLOBAL.ACTIONS.MIGRATE.mount_valid = true

if not ismastersim then return end

local Writeable = require("components/writeable")
Writeable.near_dist = 3
local _SetText = Writeable.SetText
function Writeable:SetText(text, ...)
	_SetText(self, text, ...)
	if self.onsettext then self:onsettext(text, ...) end
end
local _Write = Writeable.Write
function Writeable:Write(...)
	_Write(self, ...)
	self.inst.replica.writeable:SetWriter(nil)
end
local CanEntitySeeTarget = GLOBAL.CanEntitySeeTarget
function Writeable:OnUpdate(dt)
    if self.writer == nil then
        self.inst:StopUpdatingComponent(self)
    elseif (self.writer.components.rider ~= nil and
            self.writer.components.rider:IsRiding())
        or not (self.writer:IsNear(self.inst, self.near_dist) and
                CanEntitySeeTarget(self.writer, self.inst)) then
        self:EndWriting()
    end
end

local function UpdateName(inst)
	local name = inst.components.writeable:GetText()
	name = name and inst.owner_name .. name or inst.owner_name .. GLOBAL.STRINGS.NAMES.BEEFALO
	inst.components.named:SetName(name)
end

local function OnSave(inst, data)
    data.tendency = inst.tendency
    data.owner_name = inst.owner_name
    data.collar_owner = inst.collar_owner
end

local function OnLoad(inst, data)
    if data then
    	if data.tendency then
        	inst.tendency = data.tendency
        end
        if data.owner_name then
        	inst.owner_name = data.owner_name
        end
        if data.collar_owner then
	        inst.collar_owner = data.collar_owner
	    end
    end
end

local function BeefaloInit(inst)
	inst:AddComponent("named")
	inst.UpdateName = UpdateName
	inst:DoTaskInTime(0, inst.UpdateName)
	inst.owner_name = ""
	inst.collar_owner = nil
	inst:AddComponent("colourtweener") --for the beefalo exit/leave with player animation
	
	local _test = inst.components.trader.test
	inst.components.trader:SetAcceptTest(function(inst, item, giver, ...)
		return _test(inst, item, giver, ...) or (item.prefab == "beefalocollar" and not inst.components.combat:HasTarget() and inst.collar_owner == nil)
	end)
	
	local _onaccept = inst.components.trader.onaccept
	inst.components.trader.onaccept = function(inst, giver, item, ...)
		--inst._pre_eat_hunger = inst.components.hunger.current --need to know the actual delta hunger from eating
		_onaccept(inst, giver, item, ...)
		if item.prefab == "beefalocollar" then
			item:DoTaskInTime(0, item.Remove)
			inst.collar_owner = giver.userid
			inst:AddTag("notraptrigger")
			--print(tostring(giver.userid))
			local client = TheNet:GetClientTableForUser(giver.userid)
			inst.owner_name = client and client.name.."'s " or inst.owner_name
			inst.components.writeable:BeginWriting(giver)
		end
	end
	
	inst.OnSave = OnSave
    inst.OnLoad = OnLoad

	inst:AddComponent("writeable")
	inst.components.writeable.near_dist = 10
	inst:RemoveTag("writeable")
	inst.components.writeable.onsettext = function() inst:UpdateName() end
	inst.components.inspectable.getspecialdescription = nil --we don't want the writer to store it here
end

AddPrefabPostInit("beefalo",BeefaloInit)
if ELEMENTBEEFALO then 
	AddPrefabPostInit("firebeefalo",BeefaloInit)
	AddPrefabPostInit("icebeefalo",BeefaloInit)
	AddPrefabPostInit("lightningbeefalo",BeefaloInit)
	AddPrefabPostInit("beefaloking",BeefaloInit)
end


local Rider = require("components/rider")
local _Mount = Rider.Mount
function Rider:Mount(target, ...)
	if self.riding then return end
	if target.collar_owner and target.collar_owner ~= self.inst.userid
		and not self.inst:HasTag(tostring(target.collar_owner)) then
		--Tried mounting someone else's beefalo, push refusal events (making the beefalo attack)
		self.inst:PushEvent("refusedmount", {rider=self.inst,rideable=target})
		target:PushEvent("refusedrider", {rider=self.inst,rideable=target})
		return
	end
	return _Mount(self, target, ...)
end

local function PlayerPostInit(inst)
	inst:AddComponent("beefalosaver")
	local _OnDespawn = inst._OnDespawn or function() end
	function inst._OnDespawn(inst, ...)
		_OnDespawn(inst, ...)
		inst.components.beefalosaver:SaveBeefalo()
	end
end

for k,prefabname in ipairs(GLOBAL.DST_CHARACTERLIST) do
	AddPrefabPostInit(prefabname, PlayerPostInit)
end

if GLOBAL.MODCHARACTERLIST then
	for k,prefabname in ipairs(GLOBAL.MODCHARACTERLIST) do
		AddPrefabPostInit(prefabname, PlayerPostInit)
	end
end