using System;
using System.Collections.Generic;
using System.Linq;

using AIRuntime.Runtime.Models;
using Newtonsoft.Json.Linq;


namespace AIRuntime.Runtime.Core
{
    /// <summary>
    /// Represents the current conversation.
    /// Responsible only for storing conversation messages.
    /// </summary>
    public sealed class Conversation
    {
        private readonly List<ConversationMessage> _messages =
            new List<ConversationMessage>();


        /// <summary>
        /// Read-only conversation history.
        /// </summary>
        public IReadOnlyList<ConversationMessage> Messages =>
            _messages;


        /// <summary>
        /// Number of messages currently stored.
        /// </summary>
        public int MessageCount =>
            _messages.Count;


        /// <summary>
        /// Adds a user message.
        /// </summary>
        public void AddUserMessage(
            string content)
        {
            _messages.Add(
                new ConversationMessage
                {
                    Role =
                        "user",

                    Content =
                        content
                });
        }


        /// <summary>
        /// Adds a normal assistant message.
        /// </summary>
        public void AddAssistantMessage(
            string content)
        {
            _messages.Add(
                new ConversationMessage
                {
                    Role =
                        "assistant",

                    Content =
                        content
                });
        }


        /// <summary>
        /// Adds an assistant tool-call message.
        /// This records the fact that the model requested
        /// one or more capabilities.
        /// </summary>
        public void AddAssistantToolCalls(
            IReadOnlyList<ToolCall> toolCalls)
        {
            if (toolCalls == null)
            {
                throw new ArgumentNullException(
                    nameof(toolCalls));
            }


            _messages.Add(
                new ConversationMessage
                {
                    Role =
                        "assistant",

                    ToolCalls =
                        new List<ToolCall>(
                            toolCalls)
                });
        }


        /// <summary>
        /// Adds the result of a capability execution.
        /// </summary>
        public void AddCapabilityResult(
            string toolCallId,
            string capabilityName,
            string result)
        {
            ConversationMessage message =
                new ConversationMessage
                {
                    Role =
                        "tool",

                    ToolCallId =
                        toolCallId,

                    Name =
                        capabilityName,

                    Content =
                        result
                };

            message.Attachments = ExtractAttachments(result);
            _messages.Add(message);
        }


        private static List<ConversationAttachment> ExtractAttachments(string result)
        {
            if (string.IsNullOrWhiteSpace(result) || result[0] != '{') return null;
            try
            {
                JArray artifacts = JObject.Parse(result)["Artifacts"] as JArray;
                if (artifacts == null || artifacts.Count == 0) return null;
                List<ConversationAttachment> attachments = new List<ConversationAttachment>();
                foreach (JObject artifact in artifacts.OfType<JObject>())
                {
                    string path = artifact.Value<string>("Path") ?? artifact.Value<string>("path");
                    if (string.IsNullOrWhiteSpace(path)) continue;
                    attachments.Add(new ConversationAttachment
                    {
                        Kind = artifact.Value<string>("Kind") ?? artifact.Value<string>("kind") ?? "File",
                        Path = path,
                        MediaType = artifact.Value<string>("MediaType") ?? artifact.Value<string>("mediaType") ?? string.Empty,
                        Sha256 = artifact.Value<string>("Sha256") ?? artifact.Value<string>("sha256") ?? string.Empty,
                        Bytes = artifact.Value<long?>("Bytes") ?? artifact.Value<long?>("bytes") ?? 0
                    });
                }
                return attachments.Count == 0 ? null : attachments;
            }
            catch
            {
                return null;
            }
        }


        /// <summary>
        /// Creates a checkpoint representing the current
        /// conversation message count.
        /// </summary>
        public int CreateCheckpoint()
        {
            return _messages.Count;
        }


        /// <summary>
        /// Removes all messages added after the supplied checkpoint.
        /// </summary>
        public void RollbackToCheckpoint(
            int checkpoint)
        {
            if (
                checkpoint < 0 ||
                checkpoint > _messages.Count)
            {
                throw new ArgumentOutOfRangeException(
                    nameof(checkpoint),
                    "Checkpoint must be within the current conversation.");
            }


            int messagesToRemove =
                _messages.Count -
                checkpoint;


            if (messagesToRemove <= 0)
                return;


            _messages.RemoveRange(
                checkpoint,
                messagesToRemove);
        }


        /// <summary>
        /// Clears the complete conversation history.
        /// </summary>
        public void Clear()
        {
            _messages.Clear();
        }
    }
}
