using System;
using System.Linq;
using System.Windows.Input;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.DiagramDesigner.Models;
using SvgPathProperties;

namespace AIStudio.Wpf.DiagramDesigner
{
    public class ConnectorLabelModel : ConnectorPointModel, ISelectable
    {
        public ConnectorLabelModel(ConnectionViewModel connector, string content, double? distance = null, PointBase? offset = null) : this(null, connector, content, distance, offset)
        {
        }

        public ConnectorLabelModel(IDiagramViewModel root, ConnectionViewModel connector, string content, double? distance = null, PointBase? offset = null) : base(root)
        {
            Parent = connector;
            Text = content;
            Distance = distance;
            Offset = offset ?? new PointBase();
        }

        public ConnectorLabelModel(IDiagramViewModel root, ConnectionViewModel connector, SelectableItemBase designer) : base(root, designer)
        {
            Parent = connector;
        }

        public ConnectorLabelModel(IDiagramViewModel root, ConnectionViewModel connector, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
        {
            Parent = connector;
        }

        public override SelectableItemBase GetSerializableObject()
        {
            return new ConnectorLabelItem(this);
        }

        protected override void Init(IDiagramViewModel root, bool initNew)
        {
            base.Init(root, initNew);

            DeleteLabelCommand = new SimpleCommand(Command_Enable, DeleteLabel);
            EditCommand = new SimpleCommand(Command_Enable, ExecuteEditCommand);
        }

        protected override void InitNew()
        {
            InitIsEditing = true;
            ConnectorWidth = 30;
            ConnectorHeight = 30;
        }

        protected override void LoadDesignerItemViewModel(SelectableItemBase designerbase)
        {
            base.LoadDesignerItemViewModel(designerbase);

            if (designerbase is ConnectorLabelItem designer)
            {
                Distance = designer.Distance;
                Offset = designer.Offset;
            }
        }


        #region 属性
        public ConnectionViewModel Connector
        {
            get
            {
                return Parent as ConnectionViewModel;
            }
        }

        /// <summary>
        /// 3 types of values are possible:
        /// <para>- A number between 0 and 1: Position relative to the link's length</para>
        /// <para>- A positive number, greater than 1: Position away from the start</para>
        /// <para>- A negative number, less than 0: Position away from the end</para>
        /// </summary>
        public double? Distance
        {
            get; set;
        }
        public PointBase Offset
        {
            get; set;
        }

        public ICommand DeleteLabelCommand
        {
            get; set;
        }

        public ICommand EditCommand
        {
            get; private set;
        }
        #endregion

        private bool updating = false;

        public void UpdatePosition(SvgPath[] paths)
        {
            if (paths == null)
                return;

            var position = FindPosition(paths);
            if (position == null)
                return;

            updating = true;
            X = position.Value.X;
            Y = position.Value.Y;
            updating = false;
        }

        public PointBase? FindPosition(SvgPath[] paths)
        {
            var totalLength = paths.Sum(p => p.Length);

            double length;


            if (Distance >= 0 && Distance <= 1)
            {
                length = Distance.Value * totalLength;
            }
            else if (Distance > 1)
            {
                length = Distance.Value;
            }
            else if (Distance < 0)
            {
                length = totalLength + Distance.Value;
            }
            else
            {
                length = totalLength * (Connector.Labels.IndexOf(this) + 1) / (Connector.Labels.Count + 1);
            }


            foreach (var path in paths)
            {
                var pathLength = path.Length;
                if (length < pathLength)
                {
                    var pt = path.GetPointAtLength(length);
                    return new PointBase(pt.X + Offset.X, pt.Y + Offset.Y);
                }

                length -= pathLength;
            }

            return null;
        }

        public void UpdateOffsetX(double oldvalue, double newvalue)
        {
            if (updating == true) return;

            Offset += new VectorBase(newvalue - oldvalue, 0);
        }

        public void UpdateOffsetY(double oldvalue, double newvalue)
        {
            if (updating == true) return;

            Offset += new VectorBase(0, newvalue - oldvalue);
        }

        public override void AddToSelection(bool selected, bool clearother)
        {
            if (clearother)
            {
                foreach (var item in Connector.Labels.ToList())
                {
                    if (item != this)
                    {
                        item.IsSelected = false;
                    }
                }
            }

            IsSelected = selected;
        }

        protected override void ClearText()
        {
            Connector.RemoveLabel(this);
        }

        private void DeleteLabel(object parameter)
        {
            if (parameter is ConnectorLabelModel label)
            {
                Connector.RemoveLabel(label);
            }
        }

        protected virtual void ExecuteEditCommand(object param)
        {
            if (IsReadOnly == true) return;

            RaisePropertyChanged("ShowText");
        }
    }
}
