using System.ComponentModel;
using ColaFlow.Modules.Mcp.Application.DTOs;
using ColaFlow.Modules.Mcp.Application.Services;
using ColaFlow.Modules.Mcp.Application.Tools.Validation;
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;
using ModelContextProtocol.Server;

namespace ColaFlow.Modules.Mcp.Application.SdkTools;

/// <summary>
/// MCP Tool: create_issue (SDK-based implementation)
/// Creates a new Issue (Epic, Story, Task, or Bug)
/// Generates a Diff Preview and creates a PendingChange for approval
/// </summary>
[McpServerToolType]
public class CreateIssueSdkTool
{
    private readonly IPendingChangeService _pendingChangeService;
    private readonly IProjectRepository _projectRepository;
    private readonly ITenantContext _tenantContext;
    private readonly DiffPreviewService _diffPreviewService;
    private readonly ILogger<CreateIssueSdkTool> _logger;

    public CreateIssueSdkTool(
        IPendingChangeService pendingChangeService,
        IProjectRepository projectRepository,
        ITenantContext tenantContext,
        DiffPreviewService diffPreviewService,
        ILogger<CreateIssueSdkTool> logger)
    {
        _pendingChangeService = pendingChangeService ?? throw new ArgumentNullException(nameof(pendingChangeService));
        _projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository));
        _tenantContext = tenantContext ?? throw new ArgumentNullException(nameof(tenantContext));
        _diffPreviewService = diffPreviewService ?? throw new ArgumentNullException(nameof(diffPreviewService));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    [McpServerTool]
    [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 async Task<string> CreateIssueAsync(
        [Description("The ID of the project to create the issue in")] Guid projectId,
        [Description("Issue title (max 200 characters)")] string title,
        [Description("Issue type: Epic, Story, Task, or Bug")] string type,
        [Description("Detailed issue description (optional, max 2000 characters)")] string? description = null,
        [Description("Issue priority: Low, Medium, High, or Critical (defaults to Medium)")] string? priority = null,
        [Description("User ID to assign the issue to (optional)")] Guid? assigneeId = null,
        CancellationToken cancellationToken = default)
    {
        try
        {
            _logger.LogInformation("Executing create_issue tool (SDK)");

            // 1. Validate input
            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");

            // Parse enums
            if (!Enum.TryParse<IssueType>(type, ignoreCase: true, out var issueType))
                throw new McpInvalidParamsException($"Invalid issue type: {type}. Must be Epic, Story, Task, or Bug");

            var issuePriority = IssuePriority.Medium;
            if (!string.IsNullOrEmpty(priority))
            {
                if (!Enum.TryParse<IssuePriority>(priority, ignoreCase: true, out issuePriority))
                    throw new McpInvalidParamsException($"Invalid priority: {priority}. Must be Low, Medium, High, or Critical");
            }

            // 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 ?? string.Empty,
                type = issueType.ToString(),
                priority = issuePriority.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 = "create_issue",
                    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 $"Issue creation request submitted for approval.\n\n" +
                   $"**Pending Change ID**: {pendingChange.Id}\n" +
                   $"**Status**: Pending Approval\n" +
                   $"**Issue Type**: {issueType}\n" +
                   $"**Title**: {title}\n" +
                   $"**Priority**: {issuePriority}\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.";
        }
        catch (McpException)
        {
            throw; // Re-throw MCP exceptions as-is
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error executing create_issue tool (SDK)");
            throw new McpInvalidParamsException($"Error creating issue: {ex.Message}");
        }
    }
}
