using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Monitoring.Common;
using Monitoring.Controllers;
using Monitoring.Core.Domain.CheckListManagement;
using Monitoring.Core.Domain.EventManagement;
using Monitoring.Infrastructure.Data;

namespace Monitoring.Features.CheckListManagement;

[Route("api/checklists")]
[Authorize(Roles = Roles.Watcher)]
public class CheckListController(DataContext dataContext) : BaseController
{
	[HttpPost(Name = "CreateCheckList")]
	[ProducesResponseType<CheckListModel>(StatusCodes.Status201Created)]
	[ProducesResponseType(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Create(
		[FromBody] CreateCheckListRequest request,
		CancellationToken cancellationToken
	)
	{
		var template = await dataContext
			.CheckListTemplates.Include(t => t.Items)
			.FirstOrDefaultAsync(
				t => t.Id == new CheckListTemplateId(request.TemplateId),
				cancellationToken
			);

		if (template == null)
		{
			return NotFound("Template not found");
		}

		var alarmScope = await dataContext.AlarmScopes.FirstOrDefaultAsync(
			a => a.Id == new AlarmScopeId(request.AlarmScopeId),
			cancellationToken
		);

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

		var checkList = CheckList.Create(template.Id, alarmScope.Id);

		foreach (var templateItem in template.Items.OrderBy(i => i.Index))
		{
			var checkListItem = CheckListItem.Create(checkList.Id, templateItem.Id);
			checkList.Items.Add(checkListItem);
		}

		await dataContext.CheckLists.AddAsync(checkList, cancellationToken);
		await dataContext.SaveChangesAsync(cancellationToken);

		var model = await dataContext
			.CheckLists.Include(c => c.Items)
			.ThenInclude(i => i.Template)
			.Where(c => c.Id == checkList.Id)
			.Select(CheckListModel.Projection)
			.FirstAsync(cancellationToken);

		return CreatedAtRoute("GetCheckList", new { id = checkList.Id.Value }, model);
	}

	[HttpGet("{id:guid}", Name = "GetCheckList")]
	[ProducesResponseType<CheckListModel>(StatusCodes.Status200OK)]
	[ProducesResponseType(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Get(Guid id, CancellationToken cancellationToken)
	{
		var checkList = await dataContext
			.CheckLists.Include(c => c.Items)
			.ThenInclude(i => i.Template)
			.Where(c => c.Id == new CheckListId(id))
			.Select(CheckListModel.Projection)
			.FirstOrDefaultAsync(cancellationToken);

		if (checkList == null)
		{
			return NotFound("CheckList not found");
		}

		return Ok(checkList);
	}

	[HttpGet("by-alarm-scope/{alarmScopeId:guid}", Name = "GetCheckListByAlarmScope")]
	[ProducesResponseType<CheckListModel>(StatusCodes.Status200OK)]
	[ProducesResponseType(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> GetByAlarmScope(
		Guid alarmScopeId,
		CancellationToken cancellationToken
	)
	{
		var checkList = await dataContext
			.CheckLists.Include(c => c.Items)
			.ThenInclude(i => i.Template)
			.Where(c => c.AlarmScopeId == new AlarmScopeId(alarmScopeId))
			.Select(CheckListModel.Projection)
			.FirstOrDefaultAsync(cancellationToken);

		if (checkList == null)
		{
			return NotFound("CheckList not found");
		}

		return Ok(checkList);
	}

	[HttpPut("items/{itemId:guid}/check", Name = "CheckCheckListItem")]
	[ProducesResponseType(StatusCodes.Status204NoContent)]
	[ProducesResponseType(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> CheckItem(Guid itemId, CancellationToken cancellationToken)
	{
		var item = await dataContext.CheckListItems.FirstOrDefaultAsync(
			i => i.Id == new CheckListItemId(itemId),
			cancellationToken
		);

		if (item == null)
		{
			return NotFound("CheckList item not found");
		}

		item.MarkAsChecked();
		await dataContext.SaveChangesAsync(cancellationToken);

		return NoContent();
	}

	[HttpPut("items/{itemId:guid}/uncheck", Name = "UncheckCheckListItem")]
	[ProducesResponseType(StatusCodes.Status204NoContent)]
	[ProducesResponseType(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> UncheckItem(Guid itemId, CancellationToken cancellationToken)
	{
		var item = await dataContext.CheckListItems.FirstOrDefaultAsync(
			i => i.Id == new CheckListItemId(itemId),
			cancellationToken
		);

		if (item == null)
		{
			return NotFound("CheckList item not found");
		}

		item.MarkAsUnchecked();
		await dataContext.SaveChangesAsync(cancellationToken);

		return NoContent();
	}
}

public record CreateCheckListRequest(Guid TemplateId, Guid AlarmScopeId);
