using System.ComponentModel;
using ColaFlow.Modules.Mcp.Application.DTOs;
using ColaFlow.Modules.Mcp.Application.Services;
using ColaFlow.Modules.Mcp.Domain.Exceptions;
using ColaFlow.Modules.Mcp.Domain.Services;
using ColaFlow.Modules.IssueManagement.Domain.Enums;
using ColaFlow.Modules.IssueManagement.Domain.Repositories;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;

namespace ColaFlow.Modules.Mcp.Application.SdkTools;

/// <summary>
/// MCP Tool: update_status (SDK-based implementation)
/// Updates the status of an existing Issue
/// Generates a Diff Preview and creates a PendingChange for approval
/// </summary>
[McpServerToolType]
public class UpdateStatusSdkTool
{
    private readonly IPendingChangeService _pendingChangeService;
    private readonly IIssueRepository _issueRepository;
    private readonly DiffPreviewService _diffPreviewService;
    private readonly ILogger<UpdateStatusSdkTool> _logger;

    public UpdateStatusSdkTool(
        IPendingChangeService pendingChangeService,
        IIssueRepository issueRepository,
        DiffPreviewService diffPreviewService,
        ILogger<UpdateStatusSdkTool> logger)
    {
        _pendingChangeService = pendingChangeService ?? throw new ArgumentNullException(nameof(pendingChangeService));
        _issueRepository = issueRepository ?? throw new ArgumentNullException(nameof(issueRepository));
        _diffPreviewService = diffPreviewService ?? throw new ArgumentNullException(nameof(diffPreviewService));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    [McpServerTool]
    [Description("Update the status of an existing issue. Supports workflow transitions (Backlog → Todo → InProgress → Done). Requires human approval before being applied.")]
    public async Task<string> UpdateStatusAsync(
        [Description("The ID of the issue to update")] Guid issueId,
        [Description("The new status: Backlog, Todo, InProgress, or Done")] string newStatus,
        CancellationToken cancellationToken = default)
    {
        try
        {
            _logger.LogInformation("Executing update_status tool (SDK)");

            // 1. Validate and parse status
            if (!Enum.TryParse<IssueStatus>(newStatus, ignoreCase: true, out var statusEnum))
                throw new McpInvalidParamsException($"Invalid status: {newStatus}. Must be Backlog, Todo, InProgress, or Done");

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

            var oldStatus = issue.Status;

            // 3. Build before and after data for diff preview
            var beforeData = new
            {
                id = issue.Id,
                title = issue.Title,
                type = issue.Type.ToString(),
                status = oldStatus.ToString(),
                priority = issue.Priority.ToString()
            };

            var afterData = new
            {
                id = issue.Id,
                title = issue.Title,
                type = issue.Type.ToString(),
                status = statusEnum.ToString(), // Only status changed
                priority = issue.Priority.ToString()
            };

            // 4. Generate Diff Preview (UPDATE operation)
            var diff = _diffPreviewService.GenerateUpdateDiff(
                entityType: "Issue",
                entityId: issueId,
                beforeEntity: beforeData,
                afterEntity: afterData,
                entityKey: $"{issue.Type}-{issue.Id.ToString().Substring(0, 8)}"
            );

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

            _logger.LogInformation(
                "PendingChange created: {PendingChangeId} - UPDATE Issue {IssueId} status: {OldStatus} → {NewStatus}",
                pendingChange.Id, issueId, oldStatus, statusEnum);

            // 6. Return pendingChangeId to AI
            return $"Issue status update request submitted for approval.\n\n" +
                   $"**Pending Change ID**: {pendingChange.Id}\n" +
                   $"**Status**: Pending Approval\n" +
                   $"**Issue**: {issue.Title}\n" +
                   $"**Old Status**: {oldStatus}\n" +
                   $"**New Status**: {statusEnum}\n\n" +
                   $"A human user must approve this change before the issue status is updated. " +
                   $"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 update_status tool (SDK)");
            throw new McpInvalidParamsException($"Error updating issue status: {ex.Message}");
        }
    }
}
