using MediatR;
using ColaFlow.Modules.ProjectManagement.Application.DTOs;
using ColaFlow.Modules.ProjectManagement.Application.Common.Interfaces;
using ColaFlow.Modules.ProjectManagement.Domain.Repositories;
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
using ColaFlow.Modules.ProjectManagement.Domain.Exceptions;

namespace ColaFlow.Modules.ProjectManagement.Application.Queries.GetEpicById;

/// <summary>
/// Handler for GetEpicByIdQuery
/// </summary>
public sealed class GetEpicByIdQueryHandler(
    IProjectRepository projectRepository,
    ITenantContext tenantContext)
    : IRequestHandler<GetEpicByIdQuery, EpicDto>
{
    private readonly IProjectRepository _projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository));
    private readonly ITenantContext _tenantContext = tenantContext ?? throw new ArgumentNullException(nameof(tenantContext));

    public async Task<EpicDto> Handle(GetEpicByIdQuery request, CancellationToken cancellationToken)
    {
        // Get current tenant ID (Defense in Depth - Layer 2)
        var currentTenantId = _tenantContext.GetCurrentTenantId();

        // Use read-only method for query (AsNoTracking for better performance)
        var epicId = EpicId.From(request.EpicId);
        var epic = await _projectRepository.GetEpicByIdReadOnlyAsync(epicId, cancellationToken);

        if (epic == null)
            throw new NotFoundException("Epic", request.EpicId);

        // CRITICAL SECURITY: Explicit TenantId validation (Defense in Depth)
        // Even though EF Core global query filters should prevent cross-tenant access,
        // we explicitly verify tenant ownership to ensure defense in depth.
        if (epic.TenantId.Value != currentTenantId)
            throw new NotFoundException("Epic", request.EpicId);

        return new EpicDto
        {
            Id = epic.Id.Value,
            Name = epic.Name,
            Description = epic.Description,
            ProjectId = epic.ProjectId.Value,
            Status = epic.Status.Name,
            Priority = epic.Priority.Name,
            CreatedBy = epic.CreatedBy.Value,
            CreatedAt = epic.CreatedAt,
            UpdatedAt = epic.UpdatedAt,
            Stories = epic.Stories.Select(s => new StoryDto
            {
                Id = s.Id.Value,
                Title = s.Title,
                Description = s.Description,
                EpicId = s.EpicId.Value,
                Status = s.Status.Name,
                Priority = s.Priority.Name,
                EstimatedHours = s.EstimatedHours,
                ActualHours = s.ActualHours,
                AssigneeId = s.AssigneeId?.Value,
                CreatedBy = s.CreatedBy.Value,
                CreatedAt = s.CreatedAt,
                UpdatedAt = s.UpdatedAt,
                Tasks = s.Tasks.Select(t => new TaskDto
                {
                    Id = t.Id.Value,
                    Title = t.Title,
                    Description = t.Description,
                    StoryId = t.StoryId.Value,
                    Status = t.Status.Name,
                    Priority = t.Priority.Name,
                    AssigneeId = t.AssigneeId?.Value,
                    EstimatedHours = t.EstimatedHours,
                    ActualHours = t.ActualHours,
                    CreatedBy = t.CreatedBy.Value,
                    CreatedAt = t.CreatedAt,
                    UpdatedAt = t.UpdatedAt
                }).ToList()
            }).ToList()
        };
    }
}
