using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using AIRuntime.Runtime.Capabilities;
using AIRuntime.Runtime.Capabilities.Attributes;
using AIRuntime.Runtime.Capabilities.Permissions;


namespace AIRuntime.Editor
{
    [Serializable]
    public sealed class CreateKanbanChildTaskArguments
    {
        [Required]
        [Description("Short title for the new child task.")]
        public string Title { get; set; }

        [Description("Non-empty, complete work the child agent must complete.")]
        public string Description { get; set; }

        [Description("Non-empty, concrete conditions required for the child task to pass review.")]
        public string AcceptanceCriteria { get; set; }

        [Description("Optional saved Kanban agent ID. Omit to inherit the parent task's assigned agent.")]
        public string AssignedAgent { get; set; }

        [Description("Optional exact title of a sibling that must be Done before this child can run. The sibling may be restated later in the same Planning snapshot. When omitted, AIRuntime only sequences after a sibling proposed earlier in this same Planning run; pre-existing cards are never selected implicitly.")]
        public string DependsOnSiblingTitle { get; set; }

        [Description("Optional exact titles of every sibling that must be Done before this child can run. Include all producer and verification prerequisites, including forward references restated later in the same Planning snapshot. Prefer this list over DependsOnSiblingTitle when more than one prerequisite exists.")]
        public List<string> DependsOnSiblingTitles { get; set; } =
            new List<string>();

        [Description("Canonical workspace-relative artifact paths this child creates or owns, for example Assets/MyFeature/Scripts/Controller.cs. Use exact persistent paths, not prose or folder scope.")]
        public List<string> ProducesArtifactPaths { get; set; } =
            new List<string>();

        [Description("Canonical workspace-relative artifact paths this child reads, attaches, verifies, or otherwise consumes from producer siblings.")]
        public List<string> ConsumesArtifactPaths { get; set; } =
            new List<string>();

        [Description("Canonical keys for shared mutable resources this child changes or verifies, for example scene:Assets/MyFeature/Scenes/Main.unity. Every card sharing a mutable key must be dependency-ordered.")]
        public List<string> MutatesResourceKeys { get; set; } =
            new List<string>();

        [DefaultValue(false)]
        [Description("Set true only when this child is genuinely independent and may run concurrently with previously created siblings.")]
        public bool CanRunInParallel { get; set; }

        [DefaultValue("Normal")]
        [Description("Child priority: Low, Normal, High, or Critical.")]
        public string Priority { get; set; } =
            "Normal";
    }


    [Serializable]
    internal sealed class CreateKanbanChildTaskResult
    {
        public bool Succeeded;
        public string Error;
        public string ParentTaskId;
        public string ParentTitle;
        public string ChildTaskId;
        public string ChildTitle;
        public string ChildStatus;
        public string AssignedAgent;
        public string DependsOnSiblingTitle;
        public List<string> DependsOnSiblingTitles =
            new List<string>();
        public List<string> ProducesArtifactPaths =
            new List<string>();
        public List<string> ConsumesArtifactPaths =
            new List<string>();
        public List<string> MutatesResourceKeys =
            new List<string>();
        public int DirectChildCount;
        public string ResponseInstruction =
            "The card is included in the current Planning snapshot and remains ineligible to start until AIRuntime reconciles and approves the complete graph. Restate every desired direct child before returning; omitted proposal cards are retired.";
    }


    [Serializable]
    public sealed class CommitKanbanPlanArguments
    {
        [DefaultValue(1)]
        [Description("One-based commit attempt within this Planning run. Start at 1 and increment only after commit_kanban_plan reports a validation error.")]
        public int CommitSequence { get; set; } = 1;
    }


    [Serializable]
    internal sealed class CommitKanbanPlanResult
    {
        public bool Succeeded;
        public string Error;
        public string ParentTaskId;
        public string ParentTitle;
        public string PlanningAttemptId;
        public int ProposedChildCount;
        public string ResponseInstruction;
    }


    public interface IKanbanTaskExecutionServices
    {
        object ReadTaskContext();

        object CreateChildTask(
            CreateKanbanChildTaskArguments arguments);

        object CommitPlan();
    }


    internal sealed class DelegateKanbanTaskExecutionServices :
        IKanbanTaskExecutionServices,
        IKanbanCardMemoryServices,
        IKanbanRunIdentity,
        IServiceProvider
    {
        private readonly Func<object> _read;
        private readonly Func<CreateKanbanChildTaskArguments, object> _create;
        private readonly Func<object> _commit;
        private readonly Func<SaveKanbanCheckpointArguments, object> _saveMemory;
        private readonly Func<ReadKanbanMemoryArguments, object> _readMemory;

        public string RunId { get; }


        public DelegateKanbanTaskExecutionServices(
            Func<object> read,
            Func<CreateKanbanChildTaskArguments, object> create,
            string runId = null,
            Func<object> commit = null,
            Func<SaveKanbanCheckpointArguments, object> saveMemory = null,
            Func<ReadKanbanMemoryArguments, object> readMemory = null)
        {
            if (read == null)
            {
                throw new ArgumentNullException(
                    nameof(read));
            }

            _read = read;
            _create = create;
            _commit = commit;
            _saveMemory = saveMemory;
            _readMemory = readMemory;
            RunId = runId;
        }


        public object CommitPlan()
        {
            if (_commit == null)
            {
                throw new InvalidOperationException(
                    "commit_kanban_plan is available only during the Planning / Orchestration phase.");
            }

            return _commit();
        }


        public object ReadTaskContext()
        {
            return _read();
        }


        public object CreateChildTask(
            CreateKanbanChildTaskArguments arguments)
        {
            if (_create == null)
            {
                throw new InvalidOperationException(
                    "create_kanban_child_task is available only during the Planning / Orchestration phase.");
            }

            return _create(arguments);
        }


        public object SaveCheckpoint(SaveKanbanCheckpointArguments args) =>
            _saveMemory != null ? _saveMemory(args) : throw new InvalidOperationException("Card memory is unavailable.");

        public object ReadMemory(ReadKanbanMemoryArguments args) =>
            _readMemory != null ? _readMemory(args) : throw new InvalidOperationException("Card memory is unavailable.");

        public object GetService(
            Type serviceType)
        {
            return serviceType == typeof(IKanbanTaskExecutionServices) ||
                   serviceType == typeof(IKanbanCardMemoryServices) ||
                   serviceType == typeof(IKanbanRunIdentity)
                ? this
                : null;
        }
    }


    [Serializable]
    public sealed class GetKanbanTaskContextArguments
    {
    }


    public sealed class GetKanbanTaskContextCapability :
        CapabilityBase<GetKanbanTaskContextArguments>
    {
        private readonly IKanbanTaskExecutionServices _services;


        public GetKanbanTaskContextCapability()
        {
        }


        public GetKanbanTaskContextCapability(
            IKanbanTaskExecutionServices services)
        {
            _services = services;
        }


        public override string Name =>
            "get_kanban_task_context";


        public override string Description =>
            "Returns authoritative metadata for the currently executing Kanban card, including its parent relationship, status, assignment, creation source, and child counts. It cannot inspect unrelated cards.";


        public override CapabilityPermission Permission =>
            CapabilityPermission.ReadOnly;


        protected override Task<object> ExecuteAsync(
            GetKanbanTaskContextArguments arguments,
            CapabilityContext context)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            if (_services == null)
            {
                throw new InvalidOperationException(
                    "get_kanban_task_context requires a Kanban run-scoped task service.");
            }

            return Task.FromResult(
                _services.ReadTaskContext());
        }
    }


    public sealed class CreateKanbanChildTaskCapability :
        CapabilityBase<CreateKanbanChildTaskArguments>,
        ICapabilityExecutionSemantics
    {
        private readonly IKanbanTaskExecutionServices _services;


        public CreateKanbanChildTaskCapability()
        {
        }


        public CreateKanbanChildTaskCapability(
            IKanbanTaskExecutionServices services)
        {
            _services = services;
        }


        public override string Name =>
            "create_kanban_child_task";


        public override string Description =>
            "During the Planning / Orchestration phase, creates or revises a To Do implementation card under the currently executing Kanban task, which is the project root for that phase. The parent identity is supplied securely by the Kanban runner and cannot be chosen by the model. Implementation and Final Review runs cannot mutate the task graph.";


        public override CapabilityPermission Permission =>
            CapabilityPermission.Write;


        public CapabilityBatchBehavior BatchBehavior =>
            CapabilityBatchBehavior.AllowSameCapabilityBatch;


        public CapabilityRepeatedCallBehavior RepeatedCallBehavior =>
            CapabilityRepeatedCallBehavior.ReplayPreviousResult;


        protected override Task<object> ExecuteAsync(
            CreateKanbanChildTaskArguments arguments,
            CapabilityContext context)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            if (arguments == null)
                throw new ArgumentNullException(nameof(arguments));

            if (string.IsNullOrWhiteSpace(arguments.Title))
                throw new ArgumentException(
                    "Title is required.",
                    nameof(arguments.Title));

            if (_services == null)
            {
                throw new InvalidOperationException(
                    "create_kanban_child_task requires a Kanban run-scoped task service.");
            }

            return Task.FromResult(
                _services.CreateChildTask(
                    arguments));
        }
    }


    public sealed class CommitKanbanPlanCapability :
        CapabilityBase<CommitKanbanPlanArguments>,
        ICapabilityExecutionSemantics
    {
        private readonly IKanbanTaskExecutionServices _services;


        public CommitKanbanPlanCapability()
        {
        }


        public CommitKanbanPlanCapability(
            IKanbanTaskExecutionServices services)
        {
            _services = services;
        }


        public override string Name =>
            "commit_kanban_plan";


        public override string Description =>
            "Validates and durably accepts the complete Planning snapshot for the current parent. Call this exactly once after creating or revising every desired direct child. A successful result is authoritative even if the provider fails while producing a later prose summary.";


        public override CapabilityPermission Permission =>
            CapabilityPermission.Write;


        public CapabilityBatchBehavior BatchBehavior =>
            CapabilityBatchBehavior.SingleMutationPerResponse;


        public CapabilityRepeatedCallBehavior RepeatedCallBehavior =>
            CapabilityRepeatedCallBehavior.ReplayPreviousResult;


        protected override Task<object> ExecuteAsync(
            CommitKanbanPlanArguments arguments,
            CapabilityContext context)
        {
            context.CancellationToken.ThrowIfCancellationRequested();

            if (_services == null)
            {
                throw new InvalidOperationException(
                    "commit_kanban_plan requires a Kanban run-scoped task service.");
            }

            return Task.FromResult(
                _services.CommitPlan());
        }
    }
}
