using System;
using System.Linq;
using UnityEngine;
using UnityEngine.Timeline;

namespace UnityEditor.Timeline
{
    class TrimItemModeReplace : ITrimItemMode, ITrimItemDrawer
    {
        ITrimmable m_Item;

        ITrimmable m_ItemToBeReplaced;
        double m_ClipOriginalEdgeValue;
        bool m_TrimReplace;

        double m_Min;
        double m_Max;

        public void OnBeforeTrim(ITrimmable item, TrimEdge trimDirection)
        {
            m_Item = item;

            var sortedClips = ItemsUtils.GetItemsExcept(item.parentTrack, new[] { item })
                .OfType<ITrimmable>()
                .OrderBy(c => c.start);

            var clipStart = (DiscreteTime)item.start;
            var clipEnd = (DiscreteTime)item.end;

            var overlapped = sortedClips.LastOrDefault(c => (DiscreteTime)c.start == clipStart && (DiscreteTime)c.end == clipEnd);

            ITrimmable nextItem;
            ITrimmable prevItem;

            m_Min = 0.0;
            m_Max = double.PositiveInfinity;

            if (trimDirection == TrimEdge.Start)
            {
                nextItem = sortedClips.FirstOrDefault(c => (DiscreteTime)c.start >= clipStart && (DiscreteTime)c.end > clipEnd);
                prevItem = sortedClips.LastOrDefault(c => (DiscreteTime)c.start <= clipStart && (DiscreteTime)c.end < clipEnd);

                if (prevItem != null)
                    m_Min = prevItem.start + EditModeUtils.BlendDuration(prevItem, TrimEdge.Start) + TimelineClip.kMinDuration;

                if (nextItem != null)
                    m_Max = nextItem.start;

                m_ItemToBeReplaced = prevItem;

                if (m_ItemToBeReplaced != null)
                    m_ClipOriginalEdgeValue = m_ItemToBeReplaced.end;
            }
            else
            {
                nextItem = sortedClips.FirstOrDefault(c => c != overlapped && (DiscreteTime)c.start >= clipStart && (DiscreteTime)c.end >= clipEnd);
                prevItem = sortedClips.LastOrDefault(c => c != overlapped && (DiscreteTime)c.start <= clipStart && (DiscreteTime)c.end <= clipEnd);

                if (prevItem != null)
                    m_Min = prevItem.end;

                if (nextItem != null)
                    m_Max = nextItem.end - EditModeUtils.BlendDuration(nextItem, TrimEdge.End) - TimelineClip.kMinDuration;

                m_ItemToBeReplaced = nextItem;

                if (m_ItemToBeReplaced != null)
                    m_ClipOriginalEdgeValue = m_ItemToBeReplaced.start;
            }

            m_TrimReplace = false;
        }

        public void TrimStart(ITrimmable item, double time, bool affectTimeScale)
        {
            time = Math.Min(Math.Max(time, m_Min), m_Max);

            if (m_ItemToBeReplaced != null)
            {
                if (!m_TrimReplace)
                    m_TrimReplace = item.start >= m_ItemToBeReplaced.end;
            }

            time = Math.Max(time, 0.0);

            item.SetStart(time, affectTimeScale);

            if (m_ItemToBeReplaced != null && m_TrimReplace)
            {
                var prevEnd = Math.Min(item.start, m_ClipOriginalEdgeValue);
                m_ItemToBeReplaced.SetEnd(prevEnd, false);
            }
        }

        public void TrimEnd(ITrimmable item, double time, bool affectTimeScale)
        {
            time = Math.Min(Math.Max(time, m_Min), m_Max);

            if (m_ItemToBeReplaced != null)
            {
                if (!m_TrimReplace)
                    m_TrimReplace = item.end <= m_ItemToBeReplaced.start;
            }

            item.SetEnd(time, affectTimeScale);

            if (m_ItemToBeReplaced != null && m_TrimReplace)
            {
                var nextStart = Math.Max(item.end, m_ClipOriginalEdgeValue);
                m_ItemToBeReplaced.SetStart(nextStart, false);
            }
        }

        public void DrawGUI(WindowState state, Rect bounds, Color color, TrimEdge edge)
        {
            bool shouldDraw = m_ItemToBeReplaced != null && (edge == TrimEdge.End && m_Item.end > m_ClipOriginalEdgeValue) ||
                (edge == TrimEdge.Start && m_Item.start < m_ClipOriginalEdgeValue);

            if (shouldDraw)
            {
                var cursorType = TimelineCursors.CursorType.Replace;
                if (EditModeUtils.HasBlends(m_Item, edge))
                {
                    color = DirectorStyles.kMixToolColor;
                    cursorType = (edge == TrimEdge.End)
                        ? TimelineCursors.CursorType.MixRight
                        : TimelineCursors.CursorType.MixLeft;
                }

                EditModeGUIUtils.DrawBoundsEdge(bounds, color, edge);
                TimelineCursors.SetCursor(cursorType);
            }
            else
            {
                TimelineCursors.ClearCursor();
            }
        }
    }
}
