using System.Linq.Expressions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Monitoring.Common;
using Monitoring.Controllers;
using Monitoring.Core.Domain.AssetManagement;
using Monitoring.Core.Domain.EventManagement;
using Monitoring.Infrastructure.Data;

namespace Monitoring.Features.AlarmManagement;

[Route("api")]
[Authorize(Roles = Roles.Watcher)]
public class AlarmScopesController(DataContext dataContext) : BaseController
{
	[HttpGet("alarm-scopes", Name = "GetAlarmScopeList")]
	[ProducesResponseType<IEnumerable<AlarmScopeModel>>(StatusCodes.Status200OK)]
	[ProducesResponseType<string>(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> GetList(CancellationToken cancellationToken)
	{
		var alarmScopeList = await dataContext
			.AlarmScopes.Where(x =>
				x.Asset!.Groups.Any(x => x.Accesses.Any(x => x.Member.UserId == UserId))
			)
			.Where(x => x.StatusHistory.Count > 0)
			.GetAllowed(UserId)
			.Select(AlarmScopeModel.Projection)
			.ToListAsync(cancellationToken);

		return Ok(alarmScopeList);
	}

	[HttpGet("assets/{assetId}/alarm-scopes", Name = "GetAlarmScope")]
	[ProducesResponseType<AlarmScopeModel>(StatusCodes.Status200OK)]
	[ProducesResponseType<string>(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Get(Guid assetId, CancellationToken cancellationToken)
	{
		var assetIdValue = new AssetId(assetId);
		var alarmScope = await dataContext
			.AlarmScopes.Where(x => x.AssetId == assetIdValue)
			.Where(x => x.Asset!.Groups.Any(x => x.Accesses.Any(x => x.Member.UserId == UserId)))
			.Where(x => x.StatusHistory.Count > 0)
			.GetAllowed(UserId)
			.Select(AlarmScopeModel.Projection)
			.FirstOrDefaultAsync(cancellationToken);

		if (alarmScope is null)
		{
			return NotFound("AlarmScope not found");
		}

		return Ok(alarmScope);
	}

	[HttpGet("alarm-scopes/{alarmScopeId:guid}", Name = "GetAlarmScopeById")]
	[ProducesResponseType<AlarmScopeModel>(StatusCodes.Status200OK)]
	[ProducesResponseType<string>(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> GetById(Guid alarmScopeId, CancellationToken cancellationToken)
	{
		var alarmScopeIdValue = new AlarmScopeId(alarmScopeId);
		var alarmScope = await dataContext
			.AlarmScopes.Where(x => x.Id == alarmScopeIdValue)
			.Where(x => x.Asset!.Groups.Any(x => x.Accesses.Any(x => x.Member.UserId == UserId)))
			.Where(x => x.StatusHistory.Count > 0)
			.GetAllowed(UserId)
			.Select(AlarmScopeModel.Projection)
			.FirstOrDefaultAsync(cancellationToken);

		if (alarmScope is null)
		{
			return NotFound("AlarmScope not found");
		}

		return Ok(alarmScope);
	}
}

public record AlarmScopeModel(
	Guid Id,
	Guid AssetId,
	AlarmScopeResult Result,
	List<AlarmScopeStatusChangingModel> StatusHistory
)
{
	public static readonly Expression<Func<AlarmScope, AlarmScopeModel>> Projection =
		scope => new AlarmScopeModel(
			scope.Id.Value,
			scope.AssetId.Value,
			scope.Result,
			scope
				.StatusHistory.AsQueryable()
				.Select(AlarmScopeStatusChangingModel.Projection)
				.ToList()
		);
}
