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

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

/// <summary>
/// Handler for CreateProjectCommand
/// </summary>
public sealed class CreateProjectCommandHandler(
    IProjectRepository projectRepository,
    IUnitOfWork unitOfWork,
    ITenantContext tenantContext)
    : IRequestHandler<CreateProjectCommand, ProjectDto>
{
    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<ProjectDto> Handle(CreateProjectCommand request, CancellationToken cancellationToken)
    {
        // Get authenticated tenant ID from JWT token
        var tenantId = _tenantContext.GetCurrentTenantId();

        // Check if project key already exists
        var existingProject = await _projectRepository.GetByKeyAsync(request.Key, cancellationToken);
        if (existingProject != null)
        {
            throw new DomainException($"Project with key '{request.Key}' already exists");
        }

        // Create project aggregate with authenticated tenant ID
        var project = Project.Create(
            TenantId.From(tenantId),
            request.Name,
            request.Description,
            request.Key,
            UserId.From(request.OwnerId)
        );

        // Save to repository
        await _projectRepository.AddAsync(project, cancellationToken);
        await _unitOfWork.SaveChangesAsync(cancellationToken);

        // Return DTO
        return MapToDto(project);
    }

    private static ProjectDto MapToDto(Project project)
    {
        return new ProjectDto
        {
            Id = project.Id.Value,
            Name = project.Name,
            Description = project.Description,
            Key = project.Key.Value,
            Status = project.Status.Name,
            OwnerId = project.OwnerId.Value,
            CreatedAt = project.CreatedAt,
            UpdatedAt = project.UpdatedAt,
            Epics = new List<EpicDto>()
        };
    }
}
