using Brizco.Domain.CommandQueries.Queries;
using Brizco.Domain.Entities.Shift;
using Brizco.Domain.Entities.Task;

namespace Brizco.Core.EntityServices;

public class ActivityService : IActivityService
{
    private readonly IMediator _mediator;
    private readonly IRepositoryWrapper _repositoryWrapper;

    public ActivityService(IMediator mediator,IRepositoryWrapper repositoryWrapper)
    {
        _mediator = mediator;
        _repositoryWrapper = repositoryWrapper;
    }


    public async Task<bool> DoneActivityAsync(Guid activityId, CancellationToken cancellationToken)
    {
        var activity = await _repositoryWrapper.SetRepository<Activity>()
            .TableNoTracking
            .FirstOrDefaultAsync(a => a.Id == activityId, cancellationToken);
        if (activity == null)
            throw new AppException("Activity not found ", ApiResultStatusCode.NotFound);
        activity.DoneActivity();
        _repositoryWrapper.SetRepository<Activity>()
            .Update(activity);
        await _repositoryWrapper.SaveChangesAsync(cancellationToken);
        return true;
    }

    public async Task<bool> CompleteActivitiesAsync(List<CompleteActivityRequestDto> requestDtos, CancellationToken cancellationToken)
    {
        foreach (var activityRequestDto in requestDtos)
        {
            var activity = await _repositoryWrapper.SetRepository<Activity>().TableNoTracking
                .FirstOrDefaultAsync(a => a.Id == activityRequestDto.ActivityId, cancellationToken);
            if(activity==null)
                continue;

            activity.CompleteActivity(activityRequestDto.IsCompleted,activityRequestDto.PerformanceDescription);
            _repositoryWrapper.SetRepository<Activity>().Update(activity);
            await _repositoryWrapper.SaveChangesAsync(cancellationToken);
        }

        return true;
    }


    public async Task<bool> UnDoneActivityAsync(Guid activityId,string undoneReason, CancellationToken cancellationToken)
    {
        var activity = await _repositoryWrapper.SetRepository<Activity>()
            .TableNoTracking
            .FirstOrDefaultAsync(a => a.Id == activityId, cancellationToken);
        if (activity == null)
            throw new AppException("Activity not found ", ApiResultStatusCode.NotFound);
        activity.UnDoneActivity(undoneReason);
        _repositoryWrapper.SetRepository<Activity>()
            .Update(activity);
        await _repositoryWrapper.SaveChangesAsync(cancellationToken);
        return true;
    }

    public async Task<bool> CreateActivitiesByShiftPlan(Guid shiftPlanId,CancellationToken cancellationToken)
    {
        var shiftPlan = await _mediator.Send(new GetShiftPlanQuery(shiftPlanId), cancellationToken);
        if (shiftPlan.Id == Guid.Empty)
            return false;

        var tasks = await _repositoryWrapper.SetRepository<Brizco.Domain.Entities.Task.Task>()
            .ExecuteCommand(
                $@"SELECT t.""Id"", t.""Amount"", t.""AmountType"", t.""ComplexId"", 
t.""CreatedAt"", t.""CreatedBy"", t.""Description"", t.""Discriminator"", t.""HasDisposed"", t.""IsDisposable"", t.""IsRemoved"", t.""ModifiedAt"", 
t.""ModifiedBy"", t.""RemovedAt"", t.""RemovedBy"", t.""ScheduleType"", t.""SetFor"", t.""Title"", t.""Type"", t.""DoneAt"", t.""IsDone"", 
t.""PerformanceDescription"", t.""ShiftId"", t.""Status"", t.""UserId"" , t.""IsActivity"" , t.""UnDoneReason""
FROM public.""Tasks"" t
INNER JOIN public.""TaskShifts"" t1 ON t.""Id"" = t1.""TaskId""
INNER JOIN public.""TaskDays"" t2 ON t.""Id"" = t1.""TaskId""
INNER JOIN public.""TaskRoutines"" t3 ON t.""Id"" = t1.""TaskId""
AND {shiftPlan.ShiftId} = t1.""ShiftId""
AND {shiftPlan.RoutineId} = t3.""RoutineId""
AND {shiftPlan.PlanFor.DayOfWeek} = t2.""DayOfWeek""
GROUP BY t.""Id""").ToListAsync(cancellationToken);

        var shiftPlanPositions = await _repositoryWrapper.SetRepository<ShiftPlanUser>()
            .TableNoTracking
            .Where(spu => spu.ShiftPlanId == shiftPlan.Id)
            .ToListAsync(cancellationToken);

        foreach (var task in tasks)
        {
            var taskPositions = await _repositoryWrapper.SetRepository<TaskPosition>()
                .TableNoTracking
                .Where(tp => tp.TaskId == task.Id)
                .ToListAsync(cancellationToken);

            foreach (var taskPosition in taskPositions)
            {
                var fundedUser = shiftPlanPositions.FirstOrDefault(spu => spu.PositionId == taskPosition.PositionId);
                if (fundedUser != null)
                {
                    await _mediator.Send(new CreateActivityCommand(task.Type, task.Title, task.Description, task.IsDisposable,
                        shiftPlan.PlanFor, task.HasDisposed, task.Amount, task.AmountType, 
                        task.ScheduleType, shiftPlan.ShiftId, new List<Guid> { fundedUser.UserId }),cancellationToken);
                }
            }
        }

        return true;
    }
}