using System.Collections;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;


namespace BigSock {

	/*
		Represents the stats of an attack.
	*/
	public class AttackStats : IAttackStats {
		public static readonly System.Random RND = new System.Random();

		/*
			The damage of the attack.
		*/
		public float Damage { get; set; } = 1f;

		/*
			The knockback of the attack.
		*/
		public float Knockback { get; set; } = 1f;

		/*
			The range of the attack.
		*/
		public float Range { get; set; } = 1f;

		/*
			The projectile speed of the attack.
		*/
		public float ProjectileSpeed { get; set; } = 1f;

		/*
			The attack speed of the attack.
		*/
		public float AttackSpeed { get; set; } = 1f;

		/*
			The crit chance of the character.
		*/
		public float CritChance { get; set; }
		
		/*
			The how much to modify damage by when critting.
		*/
		public float CritDamageModifier { get; set; } = 1;
		
		/*
			How much the damage can vary in percent.
		*/
		public float DamageVariance { get; set; } = 0.2f;




		/*
			The source of the attack.
		*/
		public Vector2 Source { get; set; }

		/*
			The character that activated the attack.
		*/
		public Character Actor { get; set; }


		
		/*
			Indicates if the attack stats have been calculated.
		*/
		public bool IsCalculated { get; set; }

		/*
			Indicates if the attack was a critical hit.
		*/
		public bool IsCrit { get; set; }

		/*
			Calculates the final attack stats.
				(Takes crit and damage spread and calculates the final values)
			Cannot calculate a calculated attack.
		*/
		public IAttackStats Calculate(ICharacterStats charStats = null) {
			// Check that this attack hasn't been calculated already.
			if(IsCalculated) throw new InvalidOperationException("This attack has already been calculated!");

			// Creates return object.
			AttackStats res;
			if(charStats != null) res = (AttackStats) this.Apply(charStats);
			else                  res = Clone();

			// Mark the calculated attack as calculated.
			res.IsCalculated = true;

			// Calculate damage variety.
			var mod = (1- res.DamageVariance) + RND.NextDouble() * res.DamageVariance * 2;
			res.Damage *= (float) mod;

			// Check for crits.
			if(RND.NextDouble() <= res.CritChance) {
				res.Damage *= res.CritDamageModifier;
				res.IsCrit = true;
			}

			return res;
		}


		/*
			Creates a clone of this object.
		*/
		public AttackStats Clone() {
			return new AttackStats{
				Damage = Damage,
				Knockback = Knockback,
				Range = Range,
				ProjectileSpeed = ProjectileSpeed,
				AttackSpeed = AttackSpeed,
				CritChance = CritChance,
				CritDamageModifier = CritDamageModifier,
				
				Source = Source,
				Actor = Actor,

				DamageVariance = DamageVariance,
				IsCalculated = IsCalculated,
				IsCrit = IsCrit,
			};
		}
	}
}