using System;
using System.Collections.Generic;
using System.Linq;
using ItemComponents;
using Characters;
using Enums;
using Effects;

namespace Items
{
	/// <summary>
	/// The item class. This uses a component system whereby all the characteristics of
	/// an item and provided by the items components and can be compined in many ways.
	/// Some components do not support duplication. Reference the component documentation
	/// for specific details.
	/// </summary>
	public class Item : BaseClasses.Entity
	{
		/// <summary>
		/// Gets the mass of the item.
		/// </summary>
		/// <value>The mass of the item in terms of Constants.Mechanics.MASS_UNIT</value>
		public float Mass{ get; private set;}
		/// <summary>
		/// Gets the slot the item equips to. 
		/// May be ITEM_SLOT.NONE
		/// </summary>
		/// <value>The equip slot.</value>
		public ITEM_SLOT EquipSlot{ get; private set; }
		/// <summary>
		/// List of components the item contains, which define what functionality
		/// the item supports, and what effects it may grant.
		/// </summary>
		public List<IItemComponent> Components;
		/// <summary>
		/// The effect the item provides when consumed or equipped.
		/// It is generated by amalgamating all the effects of each item component.
		/// </summary>
		public Effect ItemEffect;
		/// <summary>
		/// Gets a value indicating whether this <see cref="Items.Item"/> should be deleted.
		/// </summary>
		/// <value><c>true</c> if the item needs to be deleted; otherwise, <c>false</c>.</value>
		public bool DeleteFlag{ get; private set; } 
		/// <summary>
		/// Initializes a new instance of the <see cref="Items.Item"/> class.
		/// </summary>
		/// <param name="name">The item's name.</param>
		/// <param name="description">The item's description.</param>
		/// <param name="mass">The mass of the item</param>
		/// <param name="components">A list of components for the item to have</param>
		/// <param name="slot">The itemslot to equip to.</param>
		public Item(string name, string description, float mass, List<IItemComponent> components, ITEM_SLOT slot){
			Name = name;
			Description = description;
			Mass = mass;
			Components=components;
			EquipSlot = slot;
			ItemEffect = new Effect();

			foreach (IGrantsEffect component in this.ComponentsOfType<IGrantsEffect>()) {
				component.ApplyEffect (this);
			}
		}
		/// <summary>
		/// Returns the list of the components of a provided type that this item has.
		/// </summary>
		/// <returns>The list components matching the provided component type</returns>
		/// <typeparam name="T">The type of itemcomponent you want a list of</typeparam>
		public List<T> ComponentsOfType<T> () where T : IItemComponent	{
			return Components.OfType<T>().ToList();
		}
		/// <summary>
		/// Gets the first component of a given type that this item has, if any.
		/// </summary>
		/// <returns>The component of the given type</returns>
		/// <typeparam name="T">The desired type of component</typeparam>
		public T FirstComponentOf<T>() where T: IItemComponent	{
			return Components.OfType<T> ().FirstOrDefault ();
		}
		/// <summary>
		/// Determines if this item supports a given component type
		/// </summary>
		/// <typeparam name="T">The type of component to check</typeparam>
		public bool Supports<T> () where T:IItemComponent{
			if (Components.OfType<T> ().Count () > 0) {
				return true;
			}
			return false;
		}
		/// <summary>
		/// Updates the item object to determine if it requires any state changes,
		/// such as checking for delete conditions of its components.
		/// </summary>
		public void Update(){
			foreach (IDestructible destroyFlag in this.ComponentsOfType<IDestructible>()) {
				if (destroyFlag.DestroyConditionMet) {
					this.DeleteFlag = true;
				}
			}
		}
		/// <summary>
		/// Adds this item to the <see cref="Characters.PlayerCharacter"/> specified's EquippedItems List,
		/// as well as adds its effect and damage components to the character's respective lists.
		/// </summary>
		/// <returns><c>true</c>, if equipping was successful, <c>false</c> otherwise.</returns>
		/// <param name="character">The character to equip the item to.</param>
		public bool EquipTo (PlayerCharacter character)	{
			if (this.EquipSlot != ITEM_SLOT.NONE && (!character.EquippedItems.Contains(this))) {
				character.StatusEffects.Add (this.ItemEffect);
				character.EquippedItems.Add(this);
				if (this.Supports<ContributesDamage> ()) {
					character.DamageComponents.Add (this.ItemEffect.DamageComponent);
				}
				return true;
			}
			return false;
		}
		/// <summary>
		/// Removes this item from the <see cref="Characters.PlayerCharacter"/> specified's EquippedItems List,
		/// as well as removes its effect and damage components from the character's respective lists.
		/// </summary>
		/// <param name="character">The character to unequip the item from.</param>
		public void UnequipFrom(PlayerCharacter character){
			if(character.EquippedItems.Contains(this)){
				character.StatusEffects.Remove(this.ItemEffect);
				character.EquippedItems.Remove(this);
				if (this.Supports<ContributesDamage> () && 
				    	character.DamageComponents.Contains(this.ItemEffect.DamageComponent)) {
					character.DamageComponents.Remove (this.ItemEffect.DamageComponent);
				}
			}
		}
		/// <summary>
		/// Consume one charge from this item. Will remove one charge from each of its
		/// consumeable components.
		/// </summary>
		public void ConsumeCharge(){
			foreach (Consumeable consumeEffect in this.ComponentsOfType<Consumeable>()) {
				consumeEffect.ConsumeCharge ();
				if (consumeEffect.DestroyConditionMet) {
					this.DeleteFlag = true;
				}
			}
			this.Update ();
		}
	}
}

