selfcare = {}
selfcare.func = {}
selfcare.form = {}
local random = math.random
local tn = tonumber
local ts = tostring

selfcare.deadly_breath = minetest.settings:get_bool("selfcare.deadly_breath") or false


--	[ registering ]

function selfcare.add_product(name, def)
    minetest.register_tool(name, def)
end

function selfcare.add_block(name, def)
    minetest.register_node(name, def)
end

function selfcare.add_item(name, def)
    minetest.register_craftitem(name, def)
end

function selfcare.add_craft(def)
    minetest.register_craft(def)
end

function selfcare.add_command(name, def)
    minetest.register_chatcommand(name, {
        description = def.info,
        func = function(param)
            return def.func(param)
        end,
    })
end

function selfcare.send(name, message)
    minetest.chat_send_player(name, message)
end

function selfcare.sendall(message)
    minetest.chat_send_all(message)
end

selfcare_tbl = {}


--	[ setting/getting attributes ]

function selfcare.set(who, what, to)
    who:set_attribute(what, to)
end

function selfcare.get(who, what)
    return who:get_attribute(what)
end


--	[ formspecs ]

function selfcare.form.Hygiene(name)
    local plyr = minetest.get_player_by_name(name)

    local s_unedited = selfcare.get(plyr, "smell") or "clean" -- the 'or' prevents crashing
    local s = (s_unedited == "bad") and "bad!" or s_unedited
    local h = selfcare.get(plyr, "hair") or "clean"
    local c = selfcare.get(plyr, "condish") or "soft"
    local t = selfcare.get(plyr, "teeth") or "white"
    local to = selfcare.get(plyr, "tongue") or "pink"
    local b = selfcare.get(plyr, "breath") or "minty"
    local p = tn(selfcare.get(plyr, "pimples")) or 0
    local fs = selfcare.get(plyr, "faceskin") or "clean" -- cleanliness
    local _fs = selfcare.get(plyr, "_faceskin") or "soft" -- dryness
    local pf = selfcare.get(plyr, "perfume") or "aren't"
    local _t = selfcare.get(plyr, "_teeth") or "nothing"
    local bdr = selfcare.get(plyr, "b_dryness") or "smooth"
    local bdi = selfcare.get(plyr, "b_dirtiness") or "clean"
    local bi = selfcare.get(plyr, "b_itchiness") or "not"

    local p_spelling = (p == 1) and " pimple" or " pimples"

    local form = "size[4.8,3.8]" ..
	"background[4.5,2;0,0;default_aspen_wood.png^[opacity:50;true]" ..
        "label[0,-0.1;You smell "..s.."]" ..
        "label[0,0.3;Your hair's "..h.." and "..c.."]" ..
        "label[0,0.7;Your teeth are "..t..", breath is "..b..",]" ..
        "label[0,1.1;tongue is "..to..", and there's ".._t.."]" ..
        "label[0,1.5;in-between your teeth.]" ..
        "label[0,1.9;You have "..p..p_spelling.."]" ..
        "label[0,2.3;Your face is "..fs.." and ".._fs.."]" ..
        "label[0,2.7;You "..pf.." wearing perfume]" ..
        "label[0,3.1;Your skin is "..bdr..", "..bdi..",]" ..
        "label[0,3.5;and "..bi.." itchy]" ..
        "button_exit[4.4,-0.2;0.6,0.2;exit;x]"

    minetest.show_formspec(name, "self_care:hygiene", form)
    return form
end


--	[ initializing ]

function selfcare.func.init(p)
    selfcare.set(p, "selfcare", "1")
    selfcare.set(p, "smell", "clean")
    selfcare.set(p, "smell_t", "0")
    selfcare.set(p, "hair", "clean")
    selfcare.set(p, "hair_t", "0")
    selfcare.set(p, "condish", "soft")
    selfcare.set(p, "condish_t", "0")
    selfcare.set(p, "teeth", "white")
    selfcare.set(p, "teeth_t", "0")
    selfcare.set(p, "_teeth", "nothing") -- in between teeth
    selfcare.set(p, "_teeth_t", "0")
    selfcare.set(p, "breath", "minty")
    selfcare.set(p, "breath_t", "0")
    selfcare.set(p, "pimples", "0")
    selfcare.set(p, "pimples_t", "0")
    selfcare.set(p, "pimpatch", "no")
    selfcare.set(p, "pimpatch_t", "0")
    selfcare.set(p, "faceskin", "clean")
    selfcare.set(p, "faceskin_t", "0")
    selfcare.set(p, "_faceskin", "soft")
    selfcare.set(p, "_faceskin_t", "0")
    selfcare.set(p, "perfume", "aren't")
    selfcare.set(p, "perfume_t", "0")
    selfcare.set(p, "b_dryness", "smooth")
    selfcare.set(p, "b_dryness_t", "0")
    selfcare.set(p, "b_dirtiness", "clean") -- dead skin cells
    selfcare.set(p, "b_dirtiness_t", "0")
    selfcare.set(p, "b_itchiness", "not")
    selfcare.set(p, "b_itchiness_t", "0")
    selfcare.set(p, "tongue", "pink")
    selfcare.set(p, "tongue_t", "0")
    selfcare.set(p, "t_whitening", "no")
    selfcare.set(p, "t_whitening_t", "0")
    selfcare.func.SetSkinType(p)
end

minetest.register_on_joinplayer(function(player)

    if not selfcare.get(player, "selfcare") then
	selfcare.func.init(player)
    end

    if not selfcare.get(player, "_teeth") then
	selfcare.set(player, "_teeth", "nothing")
	selfcare.set(player, "_teeth_t", "0")
    end
    if not selfcare.get(player, "b_dryness") then
	selfcare.set(player, "b_dryness", "smooth")
	selfcare.set(player, "b_dryness_t", "0")
    end

    if not selfcare.get(player, "b_itchiness") then
	selfcare.set(player, "b_itchiness", "not")
	selfcare.set(player, "b_itchiness_t", "0")
    end

    if not selfcare.get(player, "b_dirtiness") then
	selfcare.set(player, "b_dirtiness", "clean")
	selfcare.set(player, "b_dirtiness_t", "0")
    end

    if not selfcare.get(player, "tongue") then
	selfcare.set(player, "tongue", "pink")
	selfcare.set(player, "tongue_t", "0")
    end

    if not selfcare.get(player, "t_whitening") then
	selfcare.set(player, "t_whitening", "no")
	selfcare.set(player, "t_whitening_t", "0")
    end

    if not selfcare.get(player, "skin_type") then
	selfcare.func.SetSkinType(player)
    end
end)

--	[ tools ]

function selfcare.func.Loofah(itemstack, player, extra, pointed_thing)
    local inv = player:get_inventory()
    local n = player:get_player_name()
    local bodysoap = nil
    local foam_type


	for i = 1, inv:get_size("main") do
	    local stack = inv:get_stack("main", i)
	   -- 'if stack:get_definition().type["bodysoap"] then' didnt work
	    if  stack:get_name() == "self_care:floral_bodysoap" or
		stack:get_name() == "self_care:almond_bodysoap" then
	          bodysoap = i

		if stack:get_name() == "self_care:floral_bodysoap" then
		    foam_type = "rinsing"
		elseif stack:get_name() == "self_care:almond_bodysoap" then
		    foam_type = "foaming"
		end

	      break
	    end

	end

	if bodysoap and bodysoap > 1 then
	    local loofah_i = bodysoap - 1
	    local loofah_stack = inv:get_stack("main", loofah_i)

	  if loofah_stack:get_name() == "self_care:white_loofah" then
	      local bodysoap_stack = inv:get_stack("main", bodysoap)

		loofah_stack:add_wear(65535 / 200)
		bodysoap_stack:add_wear(65535 / 17)
		inv:set_stack("main", loofah_i, loofah_stack)
		inv:set_stack("main", bodysoap, bodysoap_stack)
		selfcare.effect.WashBody(player, extra, foam_type)

	  end

	else
		selfcare.send(n, "soap must be to the right of the loofah")

	end

	return itemstack
end

function selfcare.func.Toothbrush(itemstack, player, extra)
    local inv = player:get_inventory()
    local n = player:get_player_name()
    local toothpaste = nil


	for i = 1, inv:get_size("main") do
	    local stack = inv:get_stack("main", i)
	    if stack:get_name() == "self_care:coco_toothpaste" then
	          toothpaste = i
	      break
	    end
	end

	if toothpaste and toothpaste > 1 then
	    local brush_i = toothpaste - 1
	    local brush_stack = inv:get_stack("main", brush_i)

	  if brush_stack:get_name() == "self_care:toothbrush" or
	     brush_stack:get_name() == "self_care:wooden_toothbrush" then
	      local toothpaste_stack = inv:get_stack("main", toothpaste)

		brush_stack:add_wear(65535 / 200)
		toothpaste_stack:add_wear(65535 / 20)
		inv:set_stack("main", brush_i, brush_stack)
		inv:set_stack("main", toothpaste, toothpaste_stack)
		selfcare.effect.BrushTeeth(player, extra)

	  end

	else
		selfcare.send(n, "toothpaste must be to the right of the brush")

	end

	return itemstack
end

--	[ commands ]

selfcare.add_command("reset_selfcare", {
    info = "resets your hygiene data",
    func = function(name)
	local p = minetest.get_player_by_name(name)
	selfcare.set(p, "selfcare", nil)
	selfcare.send(name, "rejoin to reset selfcare!")
    end,
})

selfcare.add_command("skintype", {
    info = "what is my skintype",
    func = function(name)
	local p = minetest.get_player_by_name(name)
	selfcare.send(name, "your skin type: "..p:get_attribute("skin_type"))
    end,
})

function selfcare.func.stink(player)
	local pos = player:get_pos()
	local e = player:get_properties().eye_height

	minetest.add_particlespawner({
	pos = {x = pos.x, y = pos.y + e, z = pos.z},
	time = 0.1,
	amount = 1,
	vel = {min = {x = -0.8, y = -0.8, z = -0.8}, max = {x = 0.8, y = 0.8, z = 0.8}},
	acc = {min = {x = -0.8, y = -0.8, z = -0.8}, max = {x = 0.8, y = 0.8, z = 0.8}},
	size = 1,
	texture = "selfcare_stink.png^[multiply:#799363",
	collisiondetection = true,
	collision_removal = false,
	minexptime = 1,
	maxexptime = 2
	})
end

function selfcare.func.SetSkinType(player)
    local skintypes = {"oily", "normal", "dry"}
    local skin
    local tmf = random(0, 60)

	if tmf > 40 then skin = skintypes[1]
	 elseif tmf > 20 then skin = skintypes[2]
	 elseif tmf >= 0 then skin = skintypes[3]
	end

	selfcare.sendall(skin)

	player:set_attribute("skin_type", skin)
end

--	[ globalstep ]


local timer = timer or 0
minetest.register_globalstep(function(dtime)
  for _, player in ipairs(minetest.get_connected_players()) do
	local s = selfcare.get(player, "smell")
	local b = selfcare.get(player, "breath")

	if p and s ~= "bad" then
	  selfcare.func.stink(player)
	end

    if selfcare.deadly_breath == true then
	if b and b == "disgusting" then
	  local players = {}
	  local players_nearby = minetest.get_objects_inside_radius(player:get_pos(), 0.5)

	    for _, obj in ipairs(players_nearby) do
		if obj:is_player() then
		  table.insert(players, obj)
		  if obj == player then table.remove(players, tonumber(obj)) end
		end
	    end

	    if #players > 0 then
		local victim = players[math.random(#players)] -- victim fr

		  if victim:get_hp() < 4 then return end

		if victim and victim ~= nil then
		    minetest.after(timer, function()
			if victim:get_hp() < 4 then return end
			victim:set_hp(victim:get_hp() - 1)
			timer = timer + (dtime * 5)
		    end)
		end
	    else
		local victim = nil
		timer = 0
	    end
	end
    end

  end -- close for
end)