using System.Threading.Tasks;
using CSharpFunctionalExtensions;
using iText.IO.Util;
using Monitoring.Core.Domain.EventManagement;
using Monitoring.Core.Domain.UserPrimitives;
using Monitoring.Features.AlarmManagement.Skippers;
using Monitoring.Infrastructure.Data;

namespace Monitoring.Features.AlarmManagement;

public class AlarmScopeTransitionMatrix(IDataContext dataContext)
{
	public async Task<Result<AlarmScopeStatus>> GetTransitionMatrix(AlarmScope scope, UserId userId)
	{
		var currentStatusResult = GetCurrentStatus(scope);
		if (currentStatusResult.IsFailure)
		{
			return Result.Failure<AlarmScopeStatus>(currentStatusResult.Error);
		}

		var status = currentStatusResult.Value;

		do
		{
			status = Next(status);
		} while (await IsNeedToSkip(scope, status, userId));

		return status;
	}

	private async Task<bool> IsNeedToSkip(AlarmScope scope, AlarmScopeStatus status, UserId userId)
	{
		ISkipper? skipper = status switch
		{
			AlarmScopeStatus.New => new NewStatusSkipper(userId),
			AlarmScopeStatus.Accepted => new AcceptedStatusSkipper(dataContext),
			AlarmScopeStatus.CamerasViewed => new CamerasViewedStatusSkipper(dataContext),
			AlarmScopeStatus.CallsCompleted => new CallsCompletedStatusSkipper(dataContext),
			AlarmScopeStatus.CommentAndSend => new CommentAndSendStatusSkipper(),
			AlarmScopeStatus.Resolved => new ResolvedStatusSkipper(),
			_ => null,
		};

		if (skipper is null)
		{
			return false;
		}

		return await skipper.Test(scope, status);
	}

	private static Result<AlarmScopeStatus> GetCurrentStatus(AlarmScope scope)
	{
		if (scope.StatusHistory.Count == 0)
		{
			return Result.Failure<AlarmScopeStatus>("Alarm scope has no status history");
		}

		return Result.Success(
			scope.StatusHistory.OrderByDescending(x => x.CreatedAt).First().Status
		);
	}

	private static AlarmScopeStatus Next(AlarmScopeStatus currentStatus)
	{
		return currentStatus + 1;
	}
}
