using MediatR;
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;
using ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate;

namespace ColaFlow.Modules.ProjectManagement.Application.Commands.DeleteTask;

/// <summary>
/// Handler for DeleteTaskCommand
/// </summary>
public sealed class DeleteTaskCommandHandler(
    IProjectRepository projectRepository,
    IUnitOfWork unitOfWork,
    ITenantContext tenantContext)
    : IRequestHandler<DeleteTaskCommand, Unit>
{
    private readonly IProjectRepository _projectRepository = projectRepository ?? throw new ArgumentNullException(nameof(projectRepository));
    private readonly IUnitOfWork _unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
    private readonly ITenantContext _tenantContext = tenantContext ?? throw new ArgumentNullException(nameof(tenantContext));

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

        // Get the project containing the task (Global Query Filter ensures tenant isolation)
        var taskId = TaskId.From(request.TaskId);
        var project = await _projectRepository.GetProjectWithTaskAsync(taskId, cancellationToken);

        if (project == null)
            throw new NotFoundException("Task", request.TaskId);

        // CRITICAL SECURITY: Explicit TenantId validation (Defense in Depth)
        if (project.TenantId.Value != currentTenantId)
            throw new NotFoundException("Task", request.TaskId);

        // Find the story containing the task
        Story? parentStory = null;
        foreach (var epic in project.Epics)
        {
            foreach (var story in epic.Stories)
            {
                var task = story.Tasks.FirstOrDefault(t => t.Id.Value == request.TaskId);
                if (task != null)
                {
                    parentStory = story;
                    break;
                }
            }
            if (parentStory != null)
                break;
        }

        if (parentStory == null)
            throw new NotFoundException("Task", request.TaskId);

        // Remove task from story
        parentStory.RemoveTask(taskId);

        // Update project
        _projectRepository.Update(project);
        await _unitOfWork.SaveChangesAsync(cancellationToken);

        return Unit.Value;
    }
}
