using System;
using ColdMint.scripts.camp;
using ColdMint.scripts.character;
using ColdMint.scripts.damage;
using Godot;

namespace ColdMint.scripts.projectile;

/// <summary>
/// <para>Projectile template</para>
/// <para>抛射体模板</para>
/// </summary>
public partial class ProjectileTemplate : CharacterBody2D
{
	protected Timer? Timer;

	protected double Life;

	//The durability of the projectile
	//抛射体的耐久度
	//When the projectile hits the object, the durability will be reduced, and when the durability is less than or equal to 0, the projectile will be destroyed
	//当抛射体撞击到物体时,会减少耐久度,当耐久度小于等于0时,销毁抛射体
	protected double Durability;

	protected int MaxDamage;
	protected int MinDamage;
	protected int DamageType;

	//We use the Time node to specify when to destroy the projectile
	//我们用Time节点来指定何时销毁抛射体
	private Timer? _timer;

	/// <summary>
	/// <para>The impact area of the bullet</para>
	/// <para>子弹的碰撞区域</para>
	/// </summary>
	protected Area2D? Area2D;

	/// <summary>
	/// <para>knockback</para>
	/// <para>击退</para>
	/// </summary>
	/// <remarks>
	///<para>How much force does it have when hitting the character? Unit: Number of cells,The X direction of the force is inferred automatically.</para>
	///<para>当击中角色时带有多大的力?单位:格数,力的X方向是自动推断的。</para>
	/// </remarks>
	protected Vector2 KnockbackForce;

	public float Speed
	{
		get => GetMeta("Speed", "15").AsSingle();
	}

	/// <summary>
	/// <para>The master of the weapon</para>
	/// <para>武器的主人</para>
	/// </summary>
	public new Node2D? Owner { get; set; }

	public override void _Ready()
	{
		//子弹的碰撞检测区域
		Area2D = GetNode<Area2D>("CollisionDetectionArea");
		Area2D.Monitoring = true;
		Area2D.BodyEntered += OnBodyEnter;
		Area2D.BodyExited += OnBodyExited;
		Durability = GetMeta("Durability", "1").AsDouble();
		MaxDamage = GetMeta("MaxDamage", "7").AsInt32();
		MinDamage = GetMeta("MinDamage", "5").AsInt32();
		DamageType = GetMeta("DamageType", Config.DamageType.Physical).AsInt32();
		KnockbackForce = GetMeta("Knockback", Vector2.Zero).AsVector2();
		//子弹的存在时间
		Life = GetMeta("Life", "10").AsDouble();
		//如果存在时间小于等于0,那么设置为存在10秒,禁止无限期存在的抛射体
		if (Life <= 0)
		{
			Life = 10;
		}

		Timer = new Timer();
		AddChild(Timer);
		Timer.WaitTime = Life;
		Timer.OneShot = true;
		Timer.Start();
		Timer.Timeout += OnTimeOut;
	}


	/// <summary>
	/// <para>Detect whether harm is allowed</para>
	/// <para>检测是否允许造成伤害</para>
	/// </summary>
	/// <param name="owner"></param>
	/// <param name="target"></param>
	/// <returns></returns>
	private bool CanCauseHarm(Node2D? owner, Node2D target)
	{
		//We must know who the owner of the bullet is in order to determine whether it should cause damage or not
		//我们必须知道子弹的主人是谁,才能判断是否应该造成伤害
		if (owner == null)
		{
			return false;
		}

		if (owner is not CharacterTemplate ownerCharacterTemplate)
		{
			return false;
		}

		if (target is TileMap)
		{
			//When we hit the tile, we return true in order to place the bullet through the tile.
			//撞击到瓦片时,我们返回true,是为了放置子弹穿透瓦片。
			return true;
		}

		if (target is not CharacterTemplate characterTemplate)
		{
			return false;
		}

		//First get the owner's camp and compare it with the target camp
		//先获取主人的阵营与目标阵营进行比较
		var canCauseHarm = CampManager.CanCauseHarm(CampManager.GetCamp(ownerCharacterTemplate.CampId),
			CampManager.GetCamp(characterTemplate.CampId));
		return canCauseHarm;
	}

	/// <summary>
	/// <para>Executive injury treatment</para>
	/// <para>执行伤害处理</para>
	/// </summary>
	/// <param name="owner"></param>
	/// <param name="target"></param>
	private void DoDamage(Node2D? owner, Node2D target)
	{
		if (target is not CharacterTemplate characterTemplate)
		{
			return;
		}

		//Allow damage to be caused
		//允许造成伤害
		var damage = new Damage();
		damage.Attacker = owner;
		damage.MaxDamage = MaxDamage;
		damage.MinDamage = MinDamage;
		damage.CreateDamage();
		damage.MoveLeft = Velocity.X < 0;
		damage.Type = DamageType;
		characterTemplate.Damage(damage);
		if (KnockbackForce != Vector2.Zero)
		{
			//If we set the attack force, then apply the force to the object
			//如果我们设置了攻退力,那么将力应用到对象上
			var force = new Vector2();
			var forceX = Math.Abs(KnockbackForce.X);
			if (Velocity.X < 0)
			{
				//Beat back to port
				//向左击退
				forceX = -forceX;
			}

			force.X = forceX * Config.CellSize;
			force.Y = KnockbackForce.Y * Config.CellSize;
			characterTemplate.AddForce(force);
		}
	}

	/// <summary>
	/// <para>When the bullet is in contact with the node</para>
	/// <para>当子弹与节点接触时</para>
	/// </summary>
	/// <param name="node"></param>
	protected virtual void OnBodyEnter(Node2D node)
	{
		//Here we test whether harm is allowed, notice that for TileMap, we directly allow harm.
		//这里我们检测是否允许造成伤害,注意对于TileMap,我们直接允许造成伤害。
		var canCauseHarm = CanCauseHarm(Owner, node);
		if (!canCauseHarm)
		{
			return;
		}
		DoDamage(Owner, node);
		//Please specify in the Mask who the bullet will collide with
		//请在Mask内配置子弹会和谁碰撞
		//When a bullet hits an object, its durability decreases
		//子弹撞击到物体时,耐久度减少
		Durability--;
		if (Durability <= 0)
		{
			//When the durability is less than or equal to 0, destroy the bullet
			//当耐久度小于等于0时,销毁子弹
			QueueFree();
		}
	}

	/// <summary>
	/// <para>When the bullet leaves the node</para>
	/// <para>当子弹离开节点时</para>
	/// </summary>
	/// <param name="node"></param>
	protected virtual void OnBodyExited(Node2D node)
	{
	}


	/// <summary>
	/// <para>When beyond the time of existence</para>
	/// <para>当超过存在时间</para>
	/// </summary>
	private void OnTimeOut()
	{
		QueueFree();
	}

	public override void _PhysicsProcess(double delta)
	{
		MoveAndSlide();
	}
}