using System;
using System.Threading;
using System.Threading.Tasks;
using Codex.Dal;
using Codex.Dal.Entities;
using Codex.Dal.Enums;
using FluentValidation;
using Microsoft.EntityFrameworkCore;
using OpenHarbor.CQRS.Abstractions;

namespace Codex.CQRS.Commands;

/// <summary>
/// Starts a new agent execution
/// </summary>
public record StartAgentExecutionCommand
{
    /// <summary>Agent ID to execute</summary>
    public Guid AgentId { get; init; }

    /// <summary>User's input prompt</summary>
    public string UserPrompt { get; init; } = string.Empty;

    /// <summary>Optional conversation ID to link execution to</summary>
    public Guid? ConversationId { get; init; }

    /// <summary>Optional additional input context (JSON)</summary>
    public string? Input { get; init; }
}

public class StartAgentExecutionCommandHandler : ICommandHandler<StartAgentExecutionCommand, Guid>
{
    private readonly CodexDbContext _dbContext;

    public StartAgentExecutionCommandHandler(CodexDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task<Guid> HandleAsync(StartAgentExecutionCommand command, CancellationToken cancellationToken = default)
    {
        // Verify agent exists
        var agentExists = await _dbContext.Agents
            .AnyAsync(a => a.Id == command.AgentId && !a.IsDeleted, cancellationToken);

        if (!agentExists)
        {
            throw new InvalidOperationException($"Agent with ID {command.AgentId} not found or is deleted");
        }

        // Verify conversation exists if provided
        if (command.ConversationId.HasValue)
        {
            var conversationExists = await _dbContext.Conversations
                .AnyAsync(c => c.Id == command.ConversationId.Value, cancellationToken);

            if (!conversationExists)
            {
                throw new InvalidOperationException($"Conversation with ID {command.ConversationId.Value} not found");
            }
        }

        var execution = new AgentExecution
        {
            Id = Guid.NewGuid(),
            AgentId = command.AgentId,
            ConversationId = command.ConversationId,
            UserPrompt = command.UserPrompt,
            Input = command.Input,
            Output = string.Empty,
            Status = ExecutionStatus.Running,
            StartedAt = DateTime.UtcNow,
            CompletedAt = null,
            ExecutionTimeMs = null,
            InputTokens = null,
            OutputTokens = null,
            TotalTokens = null,
            EstimatedCost = null,
            ErrorMessage = null
        };

        _dbContext.AgentExecutions.Add(execution);
        await _dbContext.SaveChangesAsync(cancellationToken);

        return execution.Id;
    }
}

public class StartAgentExecutionCommandValidator : AbstractValidator<StartAgentExecutionCommand>
{
    public StartAgentExecutionCommandValidator()
    {
        RuleFor(x => x.AgentId)
            .NotEmpty().WithMessage("Agent ID is required");

        RuleFor(x => x.UserPrompt)
            .NotEmpty().WithMessage("User prompt is required")
            .MaximumLength(10000).WithMessage("User prompt cannot exceed 10000 characters");
    }
}
