using System.ComponentModel;
using System.Text.Json;
using ColaFlow.Modules.Mcp.Domain.Exceptions;
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.SdkResources;

/// <summary>
/// MCP Resource: Issues (SDK-based implementation)
/// Provides search and get functionality for Issues (Epics, Stories, Tasks)
/// </summary>
[McpServerResourceType]
public class IssuesSdkResource
{
    private readonly IProjectRepository _projectRepository;
    private readonly ITenantContext _tenantContext;
    private readonly ILogger<IssuesSdkResource> _logger;

    public IssuesSdkResource(
        IProjectRepository projectRepository,
        ITenantContext tenantContext,
        ILogger<IssuesSdkResource> logger)
    {
        _projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository));
        _tenantContext = tenantContext ?? throw new ArgumentNullException(nameof(tenantContext));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    [McpServerResource]
    [Description("Search issues with filters (status, priority, assignee, type)")]
    public async Task<string> SearchIssuesAsync(
        [Description("Filter by project ID (optional)")] Guid? project = null,
        [Description("Filter by status (optional)")] string? status = null,
        [Description("Filter by priority (optional)")] string? priority = null,
        [Description("Filter by type: epic, story, or task (optional)")] string? type = null,
        [Description("Filter by assignee ID (optional)")] Guid? assignee = null,
        [Description("Maximum number of results (default: 100)")] int limit = 100,
        [Description("Offset for pagination (default: 0)")] int offset = 0,
        CancellationToken cancellationToken = default)
    {
        var tenantId = _tenantContext.GetCurrentTenantId();

        _logger.LogDebug("Searching issues for tenant {TenantId} (SDK)", tenantId);

        // Limit max results
        limit = Math.Min(limit, 100);

        // Get projects
        var projects = await _projectRepository.GetAllProjectsReadOnlyAsync(cancellationToken);

        // Filter by project if specified
        if (project.HasValue)
        {
            var projectId = ProjectId.From(project.Value);
            var singleProject = await _projectRepository.GetProjectWithFullHierarchyReadOnlyAsync(projectId, cancellationToken);
            projects = singleProject != null ? new List<ProjectManagement.Domain.Aggregates.ProjectAggregate.Project> { singleProject } : new();
        }
        else
        {
            // Load full hierarchy for all projects
            var projectsWithHierarchy = new List<ProjectManagement.Domain.Aggregates.ProjectAggregate.Project>();
            foreach (var p in projects)
            {
                var fullProject = await _projectRepository.GetProjectWithFullHierarchyReadOnlyAsync(p.Id, cancellationToken);
                if (fullProject != null)
                {
                    projectsWithHierarchy.Add(fullProject);
                }
            }
            projects = projectsWithHierarchy;
        }

        // Collect all issues
        var allIssues = new List<object>();

        foreach (var proj in projects)
        {
            if (proj.Epics == null) continue;

            foreach (var epic in proj.Epics)
            {
                // Filter Epics
                if (ShouldIncludeIssue("epic", type, epic.Status.ToString(), status,
                    epic.Priority.ToString(), priority, null, assignee?.ToString()))
                {
                    allIssues.Add(new
                    {
                        id = epic.Id.Value,
                        type = "Epic",
                        name = epic.Name,
                        description = epic.Description,
                        status = epic.Status.ToString(),
                        priority = epic.Priority.ToString(),
                        projectId = proj.Id.Value,
                        projectName = proj.Name,
                        createdAt = epic.CreatedAt,
                        storyCount = epic.Stories?.Count ?? 0
                    });
                }

                // Filter Stories
                if (epic.Stories != null)
                {
                    foreach (var story in epic.Stories)
                    {
                        if (ShouldIncludeIssue("story", type, story.Status.ToString(), status,
                            story.Priority.ToString(), priority, story.AssigneeId?.Value.ToString(), assignee?.ToString()))
                        {
                            allIssues.Add(new
                            {
                                id = story.Id.Value,
                                type = "Story",
                                title = story.Title,
                                description = story.Description,
                                status = story.Status.ToString(),
                                priority = story.Priority.ToString(),
                                assigneeId = story.AssigneeId?.Value,
                                projectId = proj.Id.Value,
                                projectName = proj.Name,
                                epicId = epic.Id.Value,
                                epicName = epic.Name,
                                createdAt = story.CreatedAt,
                                taskCount = story.Tasks?.Count ?? 0
                            });
                        }

                        // Filter Tasks
                        if (story.Tasks != null)
                        {
                            foreach (var task in story.Tasks)
                            {
                                if (ShouldIncludeIssue("task", type, task.Status.ToString(), status,
                                    task.Priority.ToString(), priority, task.AssigneeId?.Value.ToString(), assignee?.ToString()))
                                {
                                    allIssues.Add(new
                                    {
                                        id = task.Id.Value,
                                        type = "Task",
                                        title = task.Title,
                                        description = task.Description,
                                        status = task.Status.ToString(),
                                        priority = task.Priority.ToString(),
                                        assigneeId = task.AssigneeId?.Value,
                                        projectId = proj.Id.Value,
                                        projectName = proj.Name,
                                        storyId = story.Id.Value,
                                        storyTitle = story.Title,
                                        epicId = epic.Id.Value,
                                        epicName = epic.Name,
                                        createdAt = task.CreatedAt
                                    });
                                }
                            }
                        }
                    }
                }
            }
        }

        // Apply pagination
        var total = allIssues.Count;
        var paginatedIssues = allIssues.Skip(offset).Take(limit).ToList();

        var result = JsonSerializer.Serialize(new
        {
            issues = paginatedIssues,
            total = total,
            limit = limit,
            offset = offset
        }, new JsonSerializerOptions { WriteIndented = true });

        _logger.LogInformation("Found {Count} issues for tenant {TenantId} (SDK, total: {Total})",
            paginatedIssues.Count, tenantId, total);

        return result;
    }

    private bool ShouldIncludeIssue(
        string issueType,
        string? typeFilter,
        string status,
        string? statusFilter,
        string priority,
        string? priorityFilter,
        string? assigneeId,
        string? assigneeFilter)
    {
        if (!string.IsNullOrEmpty(typeFilter) && !issueType.Equals(typeFilter, StringComparison.OrdinalIgnoreCase))
            return false;

        if (!string.IsNullOrEmpty(statusFilter) && !status.Equals(statusFilter, StringComparison.OrdinalIgnoreCase))
            return false;

        if (!string.IsNullOrEmpty(priorityFilter) && !priority.Equals(priorityFilter, StringComparison.OrdinalIgnoreCase))
            return false;

        if (!string.IsNullOrEmpty(assigneeFilter) && assigneeId != assigneeFilter)
            return false;

        return true;
    }
}
