using System.Text.Json;
using ColaFlow.Modules.Mcp.Application.DTOs;
using ColaFlow.Modules.Mcp.Application.Services;
using ColaFlow.Modules.Mcp.Application.Tools.Validation;
using ColaFlow.Modules.Mcp.Contracts.Tools;
using ColaFlow.Modules.Mcp.Domain.Exceptions;
using ColaFlow.Modules.Mcp.Domain.Services;
using ColaFlow.Modules.IssueManagement.Domain.Repositories;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace ColaFlow.Modules.Mcp.Application.Tools;

/// <summary>
/// MCP Tool: add_comment
/// Adds a comment to an existing Issue
/// Generates a Diff Preview and creates a PendingChange for approval
/// </summary>
public class AddCommentTool(
    IPendingChangeService pendingChangeService,
    IIssueRepository issueRepository,
    IHttpContextAccessor httpContextAccessor,
    DiffPreviewService diffPreviewService,
    ILogger<AddCommentTool> logger)
    : IMcpTool
{
    private readonly IPendingChangeService _pendingChangeService = pendingChangeService ?? throw new ArgumentNullException(nameof(pendingChangeService));
    private readonly IIssueRepository _issueRepository = issueRepository ?? throw new ArgumentNullException(nameof(issueRepository));
    private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
    private readonly DiffPreviewService _diffPreviewService = diffPreviewService ?? throw new ArgumentNullException(nameof(diffPreviewService));
    private readonly ILogger<AddCommentTool> _logger = logger ?? throw new ArgumentNullException(nameof(logger));

    public string Name => "add_comment";

    public string Description => "Add a comment to an existing issue. " +
                                  "Supports markdown formatting. " +
                                  "Requires human approval before being added.";

    public McpToolInputSchema InputSchema => new()
    {
        Type = "object",
        Properties = new Dictionary<string, JsonSchemaProperty>
        {
            ["issueId"] = new()
            {
                Type = "string",
                Format = "uuid",
                Description = "The ID of the issue to comment on"
            },
            ["content"] = new()
            {
                Type = "string",
                MinLength = 1,
                MaxLength = 2000,
                Description = "The comment content (supports markdown, max 2000 characters)"
            }
        },
        Required = new List<string> { "issueId", "content" }
    };

    public async Task<McpToolResult> ExecuteAsync(
        McpToolCall toolCall,
        CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation("Executing add_comment tool");

            // 1. Parse and validate input
            var issueId = ToolParameterParser.ParseGuid(toolCall.Arguments, "issueId", required: true)!.Value;
            var content = ToolParameterParser.ParseString(toolCall.Arguments, "content", required: true);

            // Validate content
            if (string.IsNullOrWhiteSpace(content))
                throw new McpInvalidParamsException("Comment content cannot be empty");

            if (content.Length > 2000)
                throw new McpInvalidParamsException("Comment content cannot exceed 2000 characters");

            // 2. Verify issue exists
            var issue = await _issueRepository.GetByIdAsync(issueId, cancellationToken);
            if (issue == null)
                throw new McpNotFoundException("Issue", issueId.ToString());

            // 3. Get API Key ID (to track who created the comment)
            var apiKeyId = _httpContextAccessor.HttpContext?.Items["ApiKeyId"] as Guid?;

            // 4. Build comment data for diff preview
            var commentData = new
            {
                issueId = issueId,
                content = content,
                authorType = "AI",
                authorId = apiKeyId,
                createdAt = DateTime.UtcNow
            };

            // 5. Generate Diff Preview (CREATE Comment operation)
            var diff = _diffPreviewService.GenerateCreateDiff(
                entityType: "Comment",
                afterEntity: commentData,
                entityKey: $"Comment on {issue.Type}-{issue.Id.ToString().Substring(0, 8)}"
            );

            // 6. Create PendingChange
            var pendingChange = await _pendingChangeService.CreateAsync(
                new CreatePendingChangeRequest
                {
                    ToolName = Name,
                    Diff = diff,
                    ExpirationHours = 24
                },
                cancellationToken);

            _logger.LogInformation(
                "PendingChange created: {PendingChangeId} - CREATE Comment on Issue {IssueId}",
                pendingChange.Id, issueId);

            // 7. Return pendingChangeId to AI
            return new McpToolResult
            {
                Content = new[]
                {
                    new McpToolContent
                    {
                        Type = "text",
                        Text = $"Comment creation request submitted for approval.\n\n" +
                               $"**Pending Change ID**: {pendingChange.Id}\n" +
                               $"**Status**: Pending Approval\n" +
                               $"**Issue**: {issue.Title}\n" +
                               $"**Comment Preview**: {(content.Length > 100 ? content.Substring(0, 100) + "..." : content)}\n\n" +
                               $"A human user must approve this change before the comment is added. " +
                               $"The change will expire at {pendingChange.ExpiresAt:yyyy-MM-dd HH:mm} UTC if not approved."
                    }
                },
                IsError = false
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error executing add_comment tool");

            return new McpToolResult
            {
                Content = new[]
                {
                    new McpToolContent
                    {
                        Type = "text",
                        Text = $"Error: {ex.Message}"
                    }
                },
                IsError = true
            };
        }
    }
}
