using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using AIRuntime.Runtime.Providers;

using UnityEditor;
using UnityEngine;


namespace AIRuntime.Editor
{
    /// <summary>
    /// Dockable view of safe, observable agent work. The window intentionally
    /// excludes provider payloads and private model reasoning.
    /// </summary>
    public sealed class AIRuntimeAgentActivityWindow :
        EditorWindow
    {
        private const float RunListWidth =
            270f;

        [SerializeField]
        private bool _activeOnly;

        [SerializeField] private int _readableFeedVersion;

        [SerializeField]
        private bool _autoScroll =
            true;

        [SerializeField]
        private string _search =
            string.Empty;

        [SerializeField]
        private string _selectedCorrelationId =
            string.Empty;

        private readonly Dictionary<long, bool> _expandedDetails =
            new Dictionary<long, bool>();

        private IReadOnlyList<AIRuntimeAgentActivityRun> _runs =
            Array.Empty<AIRuntimeAgentActivityRun>();

        private Vector2 _runListScroll;
        private Vector2 _timelineScroll;
        private int _pendingRefresh;
        private double _nextClockRepaint;
        private double _nextSnapshotAt;
        private ProviderTokenUsage.Totals _tokenTotals;
        private const int TimelinePageSize = 40;
        private long _timelineEndSequence = long.MaxValue;
        private string _timelineRunId;
        private readonly Dictionary<long, AIRuntimeAgentActivityExplanation> _explanations =
            new Dictionary<long, AIRuntimeAgentActivityExplanation>();

        private GUIStyle _objectiveStyle;
        private GUIStyle _timelineSummaryStyle;
        private GUIStyle _timelineDetailStyle;


        [MenuItem("Window/AIRuntime/Agent Activity")]
        public static void Open()
        {
            AIRuntimeAgentActivityWindow window =
                GetWindow<AIRuntimeAgentActivityWindow>();

            window.titleContent =
                new GUIContent(
                    "Agent Activity");

            window.minSize =
                new Vector2(
                    620f,
                    360f);

            window.Show();
            window.Focus();
            window.RefreshRuns();
        }


        private void OnEnable()
        {
            if (_readableFeedVersion < 1) { _autoScroll = false; _readableFeedVersion = 1; }
            titleContent =
                new GUIContent(
                    "Agent Activity");

            minSize =
                new Vector2(
                    620f,
                    360f);

            AIRuntimeAgentActivityStore.Shared.Changed +=
                OnActivityChanged;

            RefreshRuns();
        }


        private void OnDisable()
        {
            AIRuntimeAgentActivityStore.Shared.Changed -=
                OnActivityChanged;
        }


        private void Update()
        {
            var totals = ProviderTokenUsage.Shared.Snapshot();
            if (totals.ReportedResponses != _tokenTotals.ReportedResponses ||
                totals.MissingResponses != _tokenTotals.MissingResponses)
            {
                _tokenTotals = totals;
                Repaint();
            }
            // Reading mode freezes the displayed snapshot, not the agent or the evidence store.
            if (!_autoScroll && Volatile.Read(ref _pendingRefresh) != 0)
            {
                if (EditorApplication.timeSinceStartup >= _nextClockRepaint)
                {
                    _nextClockRepaint = EditorApplication.timeSinceStartup + .5d;
                    Repaint();
                }
                return;
            }
            bool refresh =
                EditorApplication.timeSinceStartup >= _nextSnapshotAt &&
                Interlocked.Exchange(
                    ref _pendingRefresh,
                    0) !=
                0;

            bool clockTick =
                _runs.Any(run => run.IsActive) &&
                EditorApplication.timeSinceStartup >=
                _nextClockRepaint;

            if (clockTick)
            {
                _nextClockRepaint =
                    EditorApplication.timeSinceStartup +
                    0.5d;
            }

            if (!refresh &&
                !clockTick)
            {
                return;
            }

            if (refresh)
            {
                _nextSnapshotAt = EditorApplication.timeSinceStartup + .25d;
                RefreshRuns();

                if (_autoScroll)
                {
                    _timelineEndSequence = long.MaxValue;
                    _timelineScroll.y =
                        float.MaxValue;
                }
            }

            Repaint();
        }


        private void OnGUI()
        {
            EnsureStyles();
            DrawToolbar();
            DrawTokenUsage();
            if (!_autoScroll)
            {
                using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox))
                {
                    GUILayout.Label(Volatile.Read(ref _pendingRefresh) != 0
                        ? "New activity available. Your reading position is held."
                        : "Reading mode — the agent continues working.", EditorStyles.wordWrappedMiniLabel);
                    if (GUILayout.Button("Show latest", GUILayout.Width(85f)))
                    {
                        RefreshRuns();
                        _timelineEndSequence = long.MaxValue;
                        _timelineScroll.y = float.MaxValue;
                    }
                }
            }

            EditorGUILayout.HelpBox(
                "Follow what the agent is doing, what it is working on, and what happened. Likely purpose is inferred from the action, not supplied by the provider.",
                MessageType.Info);

            IReadOnlyList<AIRuntimeAgentActivityRun> visibleRuns =
                GetVisibleRuns();

            if (visibleRuns.Count ==
                0)
            {
                EditorGUILayout.HelpBox(
                    _activeOnly
                        ? "No active agent runs match the current filter."
                        : "No agent activity has been recorded in this Unity domain yet.",
                    MessageType.None);

                return;
            }

            AIRuntimeAgentActivityRun selected =
                ResolveSelectedRun(
                    visibleRuns);

            using (
                new EditorGUILayout.HorizontalScope())
            {
                DrawRunList(
                    visibleRuns,
                    selected);

                GUILayout.Space(
                    6f);

                DrawRunDetails(
                    selected);
            }
        }


        private void DrawTokenUsage()
        {
            _tokenTotals = ProviderTokenUsage.Shared.Snapshot();
            const string explanation = "Provider-reported input and output tokens across all requests in this Unity domain, including chat, retries and fallback providers. " +
                "Updated when each response finishes. Input includes resent conversation history and cached tokens. Counts reset on script reload or Editor restart.";
            using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
            {
                using (new EditorGUILayout.HorizontalScope())
                {
                    GUILayout.Label(new GUIContent($"Tokens sent: {_tokenTotals.Sent:N0}", explanation), EditorStyles.boldLabel);
                    GUILayout.Space(16f);
                    GUILayout.Label(new GUIContent($"Tokens received: {_tokenTotals.Received:N0}", explanation), EditorStyles.boldLabel);
                    GUILayout.FlexibleSpace();
                    if (GUILayout.Button(new GUIContent("Reset counts", "Reset token totals without clearing activity or stopping agents."), GUILayout.Width(90f)))
                        ProviderTokenUsage.Shared.Reset();
                }
                string coverage = _tokenTotals.MissingResponses > 0
                    ? $" • {_tokenTotals.MissingResponses:N0} responses did not report usage; totals are incomplete."
                    : _tokenTotals.ReportedResponses == 0 ? " • Waiting for reported usage." : "";
                GUILayout.Label($"Since last reset • {_tokenTotals.ReportedResponses:N0} responses with usage{coverage}", EditorStyles.wordWrappedMiniLabel);
            }
        }

        private void DrawToolbar()
        {
            using (
                new EditorGUILayout.HorizontalScope(
                    EditorStyles.toolbar))
            {
                GUILayout.Label(
                    "Agent Activity",
                    EditorStyles.boldLabel);

                GUILayout.Space(
                    8f);

                _activeOnly =
                    GUILayout.Toggle(
                        _activeOnly,
                        "Active only",
                        EditorStyles.toolbarButton);

                _autoScroll =
                    GUILayout.Toggle(
                        _autoScroll,
                        "Follow live",
                        EditorStyles.toolbarButton);

                GUILayout.FlexibleSpace();

                _search =
                    GUILayout.TextField(
                        _search ??
                        string.Empty,
                        EditorStyles.toolbarSearchField,
                        GUILayout.MinWidth(
                            120f),
                        GUILayout.MaxWidth(
                            260f));

                if (!string.IsNullOrEmpty(
                        _search) &&
                    GUILayout.Button(
                        "×",
                        EditorStyles.toolbarButton,
                        GUILayout.Width(
                            22f)))
                {
                    _search =
                        string.Empty;
                    GUI.FocusControl(
                        null);
                }

                if (GUILayout.Button(
                        "Clear",
                        EditorStyles.toolbarButton,
                        GUILayout.Width(
                            42f)))
                {
                    AIRuntimeAgentActivityStore.Shared.Clear();
                    _selectedCorrelationId =
                        string.Empty;
                    _expandedDetails.Clear();
                    RefreshRuns();
                }
            }
        }


        private void DrawRunList(
            IReadOnlyList<AIRuntimeAgentActivityRun> runs,
            AIRuntimeAgentActivityRun selected)
        {
            using (
                new EditorGUILayout.VerticalScope(
                    GUILayout.Width(
                        RunListWidth),
                    GUILayout.ExpandHeight(
                        true)))
            {
                EditorGUILayout.LabelField(
                    $"Runs ({runs.Count})",
                    EditorStyles.boldLabel);

                _runListScroll =
                    EditorGUILayout.BeginScrollView(
                        _runListScroll,
                        GUILayout.Width(
                            RunListWidth),
                        GUILayout.ExpandHeight(
                            true));

                foreach (
                    AIRuntimeAgentActivityRun run
                    in runs)
                {
                    DrawRunCard(
                        run,
                        ReferenceEquals(
                            run,
                            selected));
                }

                EditorGUILayout.EndScrollView();
            }
        }


        private void DrawRunCard(
            AIRuntimeAgentActivityRun run,
            bool selected)
        {
            Color priorBackground =
                GUI.backgroundColor;

            if (selected)
            {
                GUI.backgroundColor =
                    EditorGUIUtility.isProSkin
                        ? new Color(
                            0.30f,
                            0.48f,
                            0.70f)
                        : new Color(
                            0.62f,
                            0.78f,
                            0.98f);
            }

            Rect cardRect =
                EditorGUILayout.BeginVertical(
                    EditorStyles.helpBox);

            try
            {
                GUI.backgroundColor =
                    priorBackground;

                using (
                    new EditorGUILayout.HorizontalScope())
                {
                    GUILayout.Label(
                        run.Agent,
                        EditorStyles.boldLabel);

                    GUILayout.FlexibleSpace();

                    GUILayout.Label(
                        run.IsActive
                            ? "ACTIVE"
                            : GetTerminalLabel(
                                run),
                        EditorStyles.miniBoldLabel);
                }

                GUILayout.Label(
                    run.Source,
                    EditorStyles.miniLabel);

                GUILayout.Label(
                    run.Objective,
                    EditorStyles.wordWrappedMiniLabel,
                    GUILayout.MaxHeight(
                        38f));

                GUILayout.Label(
                    run.Stage,
                    EditorStyles.miniBoldLabel);
            }
            finally
            {
                EditorGUILayout.EndVertical();
                GUI.backgroundColor =
                    priorBackground;
            }

            Event current =
                Event.current;

            if (current.type ==
                    EventType.MouseUp &&
                current.button ==
                    0 &&
                cardRect.Contains(
                    current.mousePosition))
            {
                _selectedCorrelationId =
                    run.CorrelationId;
                current.Use();
                Repaint();
            }
        }


        private void DrawRunDetails(
            AIRuntimeAgentActivityRun run)
        {
            using (
                new EditorGUILayout.VerticalScope(
                    GUILayout.ExpandWidth(
                        true),
                    GUILayout.ExpandHeight(
                        true)))
            {
                using (
                    new EditorGUILayout.HorizontalScope())
                {
                    EditorGUILayout.LabelField(
                        run.Agent,
                        EditorStyles.boldLabel);

                    GUILayout.FlexibleSpace();

                    GUILayout.Label(
                        FormatDuration(
                            run),
                        EditorStyles.miniLabel);
                }

                EditorGUILayout.LabelField(
                    $"Source: {run.Source}",
                    EditorStyles.miniLabel);

                EditorGUILayout.LabelField(
                    "Objective",
                    EditorStyles.boldLabel);

                EditorGUILayout.SelectableLabel(
                    run.Objective,
                    _objectiveStyle,
                    GUILayout.MinHeight(
                        Mathf.Min(
                            92f,
                            _objectiveStyle.CalcHeight(
                                new GUIContent(
                                    run.Objective),
                                Mathf.Max(
                                    260f,
                                    position.width -
                                    RunListWidth -
                                    48f)))));

                using (
                    new EditorGUILayout.HorizontalScope(
                        EditorStyles.helpBox))
                {
                    GUILayout.Label(
                        "Current",
                        EditorStyles.miniBoldLabel,
                        GUILayout.Width(
                            48f));

                    GUILayout.Label(
                        run.Entries.Count > 0 && !string.IsNullOrWhiteSpace(run.Entries.Last().ToolName)
                            ? GetActivitySummary(GetExplanation(run.Entries.Last(), run.Entries))
                            : string.IsNullOrWhiteSpace(run.Summary)
                            ? run.Stage
                            : run.Summary,
                        EditorStyles.wordWrappedLabel);
                }

                DrawMilestones(
                    run);

                EditorGUILayout.Space(
                    4f);

                if (_timelineRunId != run.CorrelationId)
                {
                    _timelineRunId = run.CorrelationId;
                    _timelineEndSequence = long.MaxValue;
                    _timelineScroll = Vector2.zero;
                }
                int end = run.Entries.Count;
                while (end > 0 && run.Entries[end - 1].Sequence > _timelineEndSequence) end--;
                if (end == 0 && run.Entries.Count > 0) end = Math.Min(TimelinePageSize, run.Entries.Count);
                int start = Math.Max(0, end - TimelinePageSize);
                using (new EditorGUILayout.HorizontalScope())
                {
                    GUILayout.Label($"Timeline {start + (end > 0 ? 1 : 0)}–{end} of {run.Entries.Count}", EditorStyles.boldLabel);
                    GUILayout.FlexibleSpace();
                    using (new EditorGUI.DisabledScope(start == 0))
                        if (GUILayout.Button("Older", EditorStyles.miniButton))
                        {
                            _autoScroll = false;
                            _timelineEndSequence = run.Entries[start - 1].Sequence;
                            _timelineScroll = Vector2.zero;
                        }
                    using (new EditorGUI.DisabledScope(end == run.Entries.Count))
                        if (GUILayout.Button("Newer", EditorStyles.miniButton))
                        {
                            int nextEnd = Math.Min(run.Entries.Count, end + TimelinePageSize);
                            _timelineEndSequence = run.Entries[nextEnd - 1].Sequence;
                            _timelineScroll = Vector2.zero;
                        }
                    if (GUILayout.Button("Latest", EditorStyles.miniButton))
                    {
                        _timelineEndSequence = long.MaxValue;
                        _autoScroll = true;
                        _timelineScroll.y = float.MaxValue;
                    }
                }

                if (Event.current.type == EventType.ScrollWheel) _autoScroll = false;
                _timelineScroll =
                    EditorGUILayout.BeginScrollView(
                        _timelineScroll,
                        GUILayout.ExpandHeight(
                            true));

                for (int index = start; index < end; index++)
                    DrawTimelineEntry(run.Entries[index], run.Entries);

                EditorGUILayout.EndScrollView();
            }
        }


        private void DrawMilestones(
            AIRuntimeAgentActivityRun run)
        {
            using (
                new EditorGUILayout.HorizontalScope())
            {
                DrawMilestone(
                    "Started",
                    run.HasStarted,
                    !run.HasStarted &&
                    run.IsActive);

                if (run.HasToolActivity)
                {
                    DrawMilestone(
                        "Capabilities",
                        true,
                        false);
                }

                if (run.HasReviewActivity)
                {
                    DrawMilestone(
                        "Review",
                        run.HasReviewActivity,
                        run.IsActive &&
                        (run.Stage ?? string.Empty).IndexOf(
                            "review",
                            StringComparison.OrdinalIgnoreCase) >= 0);
                }

                DrawMilestone(
                    "Finished",
                    run.HasFinished,
                    false);
            }
        }


        private static void DrawMilestone(
            string label,
            bool complete,
            bool current)
        {
            string prefix =
                complete
                    ? "✓ "
                    : current
                        ? "● "
                        : "○ ";

            GUILayout.Label(
                prefix +
                label,
                current
                    ? EditorStyles.miniBoldLabel
                    : EditorStyles.miniLabel,
                GUILayout.ExpandWidth(
                    false));
        }


        private void DrawTimelineEntry(
            AIRuntimeAgentActivityEntry entry,
            IReadOnlyList<AIRuntimeAgentActivityEntry> history)
        {
            var explanation = GetExplanation(entry, history);
            using (
                new EditorGUILayout.VerticalScope(
                    EditorStyles.helpBox))
            {
                using (
                    new EditorGUILayout.HorizontalScope())
                {
                    GUILayout.Label(
                        entry.TimestampUtc.ToLocalTime()
                            .ToString("HH:mm:ss"),
                        EditorStyles.miniLabel,
                        GUILayout.Width(
                            56f));

                    GUILayout.Label(
                        GetKindLabel(
                            entry.Kind),
                        GetKindStyle(
                            entry.Kind),
                        GUILayout.Width(
                            82f));

                }
                GUILayout.Label(
                    GetActivitySummary(explanation) +
                    (entry.RepeatCount > 1 ? $"  ×{entry.RepeatCount}" : string.Empty),
                    _timelineSummaryStyle);

                if (entry.Kind == AIRuntimeAgentActivityKind.ToolFailed ||
                    entry.Kind == AIRuntimeAgentActivityKind.RunFailed ||
                    entry.Kind == AIRuntimeAgentActivityKind.Error)
                    GUILayout.Label(explanation.Outcome ?? entry.Summary, EditorStyles.wordWrappedLabel);
                if (!string.IsNullOrWhiteSpace(
                        entry.Detail))
                {
                    bool expanded =
                        _expandedDetails.TryGetValue(
                            entry.Sequence,
                            out bool stored) &&
                        stored;

                    bool next =
                        EditorGUILayout.Foldout(
                            expanded,
                            "Why / result / technical details",
                            true,
                            EditorStyles.foldoutHeader);

                    if (next !=
                        expanded)
                    {
                        _expandedDetails[
                                entry.Sequence] =
                            next;
                    }

                    if (next)
                    {
                        _autoScroll = false;
                        DrawExplanationField("Likely purpose · inferred", explanation.Purpose);
                        DrawExplanationField("Outcome", explanation.Outcome);
                        EditorGUILayout.SelectableLabel(
                            entry.Detail,
                            _timelineDetailStyle,
                            GUILayout.MinHeight(
                                Mathf.Clamp(
                                    _timelineDetailStyle.CalcHeight(
                                        new GUIContent(
                                            entry.Detail),
                                        Mathf.Max(
                                            220f,
                                            position.width -
                                            RunListWidth -
                                            70f)),
                                    34f,
                                    180f)));
                    }
                }
            }
        }

        private static void DrawExplanationField(string label, string value)
        {
            if (string.IsNullOrWhiteSpace(value)) return;
            EditorGUILayout.LabelField(label, EditorStyles.miniBoldLabel);
            GUILayout.Label(value, EditorStyles.wordWrappedLabel);
        }


        private IReadOnlyList<AIRuntimeAgentActivityRun>
            GetVisibleRuns()
        {
            IEnumerable<AIRuntimeAgentActivityRun> query =
                _runs ??
                Array.Empty<AIRuntimeAgentActivityRun>();

            if (_activeOnly)
            {
                query =
                    query.Where(
                        run =>
                            run.IsActive);
            }

            if (!string.IsNullOrWhiteSpace(
                    _search))
            {
                string search =
                    _search.Trim();

                query =
                    query.Where(
                        run =>
                            Contains(
                                run.Source,
                                search) ||
                            Contains(
                                run.Agent,
                                search) ||
                            Contains(
                                run.Objective,
                                search) ||
                            Contains(
                                run.Stage,
                                search) ||
                            Contains(
                                run.Summary,
                                search));
            }

            return query.ToArray();
        }


        private AIRuntimeAgentActivityRun ResolveSelectedRun(
            IReadOnlyList<AIRuntimeAgentActivityRun> visibleRuns)
        {
            AIRuntimeAgentActivityRun selected =
                visibleRuns.FirstOrDefault(
                    run =>
                        string.Equals(
                            run.CorrelationId,
                            _selectedCorrelationId,
                            StringComparison.Ordinal));

            if (selected ==
                null)
            {
                selected =
                    visibleRuns[0];

                _selectedCorrelationId =
                    selected.CorrelationId;
            }

            return selected;
        }


        private static string GetActivitySummary(AIRuntimeAgentActivityExplanation explanation)
        {
            string target = explanation.Target;
            return string.IsNullOrWhiteSpace(target) || target.StartsWith("Target not recorded", StringComparison.Ordinal)
                ? explanation.Action : explanation.Action + " · " + target;
        }
        private AIRuntimeAgentActivityExplanation GetExplanation(
            AIRuntimeAgentActivityEntry entry, IReadOnlyList<AIRuntimeAgentActivityEntry> history)
        {
            if (!_explanations.TryGetValue(entry.Sequence, out var explanation))
            {
                explanation = AIRuntimeAgentActivityExplanation.Build(entry, history);
                _explanations[entry.Sequence] = explanation;
            }
            return explanation;
        }

        private void RefreshRuns()
        {
            Interlocked.Exchange(ref _pendingRefresh, 0);
            _explanations.Clear();
            var snapshot = AIRuntimeAgentActivityStore.Shared.Snapshot();
            var retained = new HashSet<long>(snapshot.Select(entry => entry.Sequence));
            foreach (long key in _expandedDetails.Keys.Where(key => !retained.Contains(key)).ToArray())
                _expandedDetails.Remove(key);
            _runs =
                AIRuntimeAgentActivityProjection.BuildRuns(
                    snapshot);
        }


        private void OnActivityChanged()
        {
            Interlocked.Exchange(
                ref _pendingRefresh,
                1);
        }


        private void EnsureStyles()
        {
            if (_objectiveStyle !=
                null)
            {
                return;
            }

            _objectiveStyle =
                new GUIStyle(
                    EditorStyles.textArea)
                {
                    wordWrap = true
                };

            _timelineSummaryStyle =
                new GUIStyle(
                    EditorStyles.wordWrappedMiniLabel)
                {
                    wordWrap = true
                };

            _timelineDetailStyle =
                new GUIStyle(
                    EditorStyles.textArea)
                {
                    wordWrap = true
                };
        }


        private static GUIStyle GetKindStyle(
            AIRuntimeAgentActivityKind kind)
        {
            switch (kind)
            {
                case AIRuntimeAgentActivityKind.ToolFailed:
                case AIRuntimeAgentActivityKind.RunFailed:
                case AIRuntimeAgentActivityKind.RunTimedOut:
                case AIRuntimeAgentActivityKind.Error:
                    return EditorStyles.miniBoldLabel;

                default:
                    return EditorStyles.miniLabel;
            }
        }


        private static string GetKindLabel(
            AIRuntimeAgentActivityKind kind)
        {
            switch (kind)
            {
                case AIRuntimeAgentActivityKind.RunStarted:
                    return "START";
                case AIRuntimeAgentActivityKind.ToolStarted:
                    return "CAPABILITY";
                case AIRuntimeAgentActivityKind.ToolCompleted:
                    return "RESULT";
                case AIRuntimeAgentActivityKind.ToolFailed:
                    return "TOOL ERROR";
                case AIRuntimeAgentActivityKind.Retry:
                    return "RETRY";
                case AIRuntimeAgentActivityKind.Review:
                    return "REVIEW";
                case AIRuntimeAgentActivityKind.RunCompleted:
                    return "COMPLETE";
                case AIRuntimeAgentActivityKind.RunCancelled:
                    return "CANCELLED";
                case AIRuntimeAgentActivityKind.RunTimedOut:
                    return "TIMEOUT";
                case AIRuntimeAgentActivityKind.RunFailed:
                case AIRuntimeAgentActivityKind.Error:
                    return "ERROR";
                default:
                    return "STATUS";
            }
        }


        private static string GetTerminalLabel(
            AIRuntimeAgentActivityRun run)
        {
            AIRuntimeAgentActivityKind latest =
                run.Entries
                    .Select(
                        entry =>
                            entry.Kind)
                    .LastOrDefault(
                        kind =>
                            kind == AIRuntimeAgentActivityKind.RunCompleted ||
                            kind == AIRuntimeAgentActivityKind.RunCancelled ||
                            kind == AIRuntimeAgentActivityKind.RunTimedOut ||
                            kind == AIRuntimeAgentActivityKind.RunFailed ||
                            kind == AIRuntimeAgentActivityKind.Error);

            switch (latest)
            {
                case AIRuntimeAgentActivityKind.RunCompleted:
                    return "DONE";
                case AIRuntimeAgentActivityKind.RunCancelled:
                    return "CANCELLED";
                case AIRuntimeAgentActivityKind.RunTimedOut:
                    return "TIMEOUT";
                case AIRuntimeAgentActivityKind.RunFailed:
                case AIRuntimeAgentActivityKind.Error:
                    return "FAILED";
                default:
                    return "IDLE";
            }
        }


        private static string FormatDuration(
            AIRuntimeAgentActivityRun run)
        {
            AIRuntimeAgentActivityEntry started =
                run.Entries.FirstOrDefault(
                    entry =>
                        entry.Kind ==
                        AIRuntimeAgentActivityKind.RunStarted) ??
                run.Entries.FirstOrDefault();

            if (started ==
                null)
            {
                return string.Empty;
            }

            DateTime end =
                run.IsActive
                    ? DateTime.UtcNow
                    : run.LatestTimestampUtc;

            TimeSpan duration =
                end -
                started.TimestampUtc;

            if (duration <
                TimeSpan.Zero)
            {
                duration =
                    TimeSpan.Zero;
            }

            return duration.TotalHours >=
                   1d
                ? duration.ToString(@"h\:mm\:ss")
                : duration.ToString(@"m\:ss");
        }


        private static bool Contains(
            string value,
            string search)
        {
            return (value ?? string.Empty).IndexOf(
                       search,
                       StringComparison.OrdinalIgnoreCase) >=
                   0;
        }
    }
}
