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.Enums;
using ColaFlow.Modules.ProjectManagement.Application.Common.Interfaces;
using ColaFlow.Modules.ProjectManagement.Domain.Repositories;
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
using Microsoft.Extensions.Logging;

namespace ColaFlow.Modules.Mcp.Application.Tools;

/// <summary>
/// MCP Tool: create_issue
/// Creates a new Issue (Epic, Story, Task, or Bug)
/// Generates a Diff Preview and creates a PendingChange for approval
/// </summary>
public class CreateIssueTool(
    IPendingChangeService pendingChangeService,
    IProjectRepository projectRepository,
    ITenantContext tenantContext,
    DiffPreviewService diffPreviewService,
    ILogger<CreateIssueTool> logger)
    : IMcpTool
{
    private readonly IPendingChangeService _pendingChangeService = pendingChangeService ?? throw new ArgumentNullException(nameof(pendingChangeService));
    private readonly IProjectRepository _projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository));
    private readonly ITenantContext _tenantContext = tenantContext ?? throw new ArgumentNullException(nameof(tenantContext));
    private readonly DiffPreviewService _diffPreviewService = diffPreviewService ?? throw new ArgumentNullException(nameof(diffPreviewService));
    private readonly ILogger<CreateIssueTool> _logger = logger ?? throw new ArgumentNullException(nameof(logger));

    public string Name => "create_issue";

    public string Description => "Create a new issue (Epic, Story, Task, or Bug) in a ColaFlow project. " +
                                  "The issue will be created in 'Backlog' status and requires human approval before being created.";

    public McpToolInputSchema InputSchema => new()
    {
        Type = "object",
        Properties = new Dictionary<string, JsonSchemaProperty>
        {
            ["projectId"] = new()
            {
                Type = "string",
                Format = "uuid",
                Description = "The ID of the project to create the issue in"
            },
            ["title"] = new()
            {
                Type = "string",
                MinLength = 1,
                MaxLength = 200,
                Description = "Issue title (max 200 characters)"
            },
            ["description"] = new()
            {
                Type = "string",
                MaxLength = 2000,
                Description = "Detailed issue description (optional, max 2000 characters)"
            },
            ["type"] = new()
            {
                Type = "string",
                Enum = new[] { "Epic", "Story", "Task", "Bug" },
                Description = "Issue type"
            },
            ["priority"] = new()
            {
                Type = "string",
                Enum = new[] { "Low", "Medium", "High", "Critical" },
                Description = "Issue priority (optional, defaults to Medium)"
            },
            ["assigneeId"] = new()
            {
                Type = "string",
                Format = "uuid",
                Description = "User ID to assign the issue to (optional)"
            }
        },
        Required = new List<string> { "projectId", "title", "type" }
    };

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

            // 1. Parse and validate input
            var projectId = ToolParameterParser.ParseGuid(toolCall.Arguments, "projectId", required: true)!.Value;
            var title = ToolParameterParser.ParseString(toolCall.Arguments, "title", required: true);
            var description = ToolParameterParser.ParseString(toolCall.Arguments, "description") ?? string.Empty;
            var type = ToolParameterParser.ParseEnum<IssueType>(toolCall.Arguments, "type", required: true)!.Value;
            var priority = ToolParameterParser.ParseEnum<IssuePriority>(toolCall.Arguments, "priority") ?? IssuePriority.Medium;
            var assigneeId = ToolParameterParser.ParseGuid(toolCall.Arguments, "assigneeId");

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

            if (title.Length > 200)
                throw new McpInvalidParamsException("Issue title cannot exceed 200 characters");

            if (description.Length > 2000)
                throw new McpInvalidParamsException("Issue description cannot exceed 2000 characters");

            // 2. Verify project exists
            var project = await _projectRepository.GetByIdAsync(ProjectId.From(projectId), cancellationToken);
            if (project == null)
                throw new McpNotFoundException("Project", projectId.ToString());

            // 3. Build "after data" object for diff preview
            var afterData = new
            {
                projectId = projectId,
                title = title,
                description = description,
                type = type.ToString(),
                priority = priority.ToString(),
                status = IssueStatus.Backlog.ToString(), // Default status
                assigneeId = assigneeId
            };

            // 4. Generate Diff Preview (CREATE operation)
            var diff = _diffPreviewService.GenerateCreateDiff(
                entityType: "Issue",
                afterEntity: afterData,
                entityKey: null // No key yet (will be generated on approval)
            );

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

            _logger.LogInformation(
                "PendingChange created: {PendingChangeId} - CREATE Issue: {Title}",
                pendingChange.Id, title);

            // 6. Return pendingChangeId to AI (NOT the created issue)
            return new McpToolResult
            {
                Content = new[]
                {
                    new McpToolContent
                    {
                        Type = "text",
                        Text = $"Issue creation request submitted for approval.\n\n" +
                               $"**Pending Change ID**: {pendingChange.Id}\n" +
                               $"**Status**: Pending Approval\n" +
                               $"**Issue Type**: {type}\n" +
                               $"**Title**: {title}\n" +
                               $"**Priority**: {priority}\n" +
                               $"**Project**: {project.Name}\n\n" +
                               $"A human user must approve this change before the issue is created. " +
                               $"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 create_issue tool");

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