using Microsoft.Xna.Framework;
using MonoGame.FourEngine.Collections;
using MonoGame.FourEngine.Components;
using MonoGame.FourEngine.Interfaces;
using MonoGame.FourEngine.Resources;
using System.Collections.Generic;
using System.Linq;

namespace MonoGame.FourEngine.Entities
{
    public abstract class BasicEntity : Entity, ICanTransform, IHaveReadOnlySizeAndPosition
    {
        public ActionComponent ActionComponent { get; protected set; }
        public SpriteComponent SpriteComponent { get; protected set; }
        public AnimationComponent AnimationComponent { get; protected set; }
        
        protected abstract SpriteDefinition SpriteDefinition { get; }

        public bool Visibility
        {
            get => _visibility;
            set
            {
                _visibility = value;
                OnVisibilityChanged(value);
            }
        }
        private bool _visibility;

        public virtual Point Frame
        {
            get => SpriteComponent.Frame;
            set => SpriteComponent.Frame = value;
        }

        public virtual Point Position
        {
            get => SpriteComponent.Position;
            set => SpriteComponent.Position = value;
        }

        public virtual Color Color
        {
            get => SpriteComponent.Color;
            set => SpriteComponent.Color = value;
        }

        public int Width => SpriteComponent.Width;
        public int Height => SpriteComponent.Height;

        public ICollection<SpriteDrawHandler> Transformations { get; private set; }

        public BasicEntity()
        {
            CreateComponents();
            if (SpriteComponent != null) Visibility = true;
            Transformations = new SimpleObservableCollection<SpriteDrawHandler>(OnTransformationAdd, OnTransformationRemove);
        }

        protected virtual void CreateComponents()
        {
            Components.Add(ActionComponent = new ActionComponent(OnUpdate));
            Components.Add(SpriteComponent = new SpriteComponent(SpriteDefinition));
            Components.Add(AnimationComponent = new AnimationComponent(SpriteComponent));
        }

        public virtual void OnPrimaryClick(ClickedEventArgs args) { }

        public virtual void OnSecondaryClick(ClickedEventArgs args) { }

        public virtual void OnUpdate(UpdateEventArgs args)
        {
            if (args.Pointer == null) return;
            if (args.Pointer.HasPrimaryClicked && Contains(args.Pointer.Position))
            {
                var clickedArgs = new ClickedEventArgs(args.Scene, args.Pointer);
                OnPrimaryClick(clickedArgs);
            }
            if (args.Pointer.HasSecondaryClicked && Contains(args.Pointer.Position))
            {
                var clickedArgs = new ClickedEventArgs(args.Scene, args.Pointer);
                OnSecondaryClick(clickedArgs);
            }
        }

        public bool Contains(Point point)
        {
            foreach (SpriteComponent component in Components.Where(x => x is SpriteComponent))
                if (component.Contains(point)) return true;
            return false;
        }

        public void EnableManipulation()
            => SpriteComponent.ManipulationEnabled = true;

        protected virtual void OnVisibilityChanged(bool value)
        {
            if (value)
            {
                if (!Components.Contains(SpriteComponent))
                    Components.Add(SpriteComponent);
            }
            else
            {
                if (Components.Contains(SpriteComponent))
                    Components.Remove(SpriteComponent);
            }
        }

        private void OnTransformationAdd(SpriteDrawHandler handler)
        {
            SpriteComponent.BeforeDraw += handler;
        }

        private void OnTransformationRemove(SpriteDrawHandler handler)
        {
            SpriteComponent.BeforeDraw -= handler;
        }

        public override void Dispose()
        {
            base.Dispose();
            Transformations.Clear();
        }
    }
}