using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Monitoring.Common;
using Monitoring.Core.Domain;
using Monitoring.Core.Domain.AlarmCommentPrimitives;
using Monitoring.Core.Domain.OrganizationManagement;
using Monitoring.Features.AlarmResetComment.CreateComment;
using Monitoring.Features.AlarmResetComment.GetComment;
using Monitoring.Features.AlarmResetComment.GetListComment;
using Monitoring.Features.AlarmResetComment.UpdateComment;
using Monitoring.Infrastructure.Data;
using Monitoring.Models;

namespace Monitoring.Features.AlarmResetComment;

[Route("/api/alarm-reset-comments")]
[ApiController]
[Authorize(Roles = "Manager, Watcher")]
public class AlarmResetCommentController : ControllerBase
{
	private readonly DataContext _context;

	public AlarmResetCommentController(DataContext context)
	{
		_context = context;
	}

	[HttpPost(Name = "CreateAlarmResetComment")]
	[Authorize(Roles = Roles.Manager)]
	[ProducesResponseType<CreateRequest>(StatusCodes.Status200OK)]
	[ProducesResponseType<string>(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Create(
		[FromBody] CreateRequest request,
		CancellationToken cancellationToken
	)
	{
		var comment = new Core.Domain.AlarmResetComment(
			new AlarmResetCommentId(Guid.NewGuid()),
			new OrganizationId(request.OrganizationId)
		);

		foreach (var translate in request.Translates)
		{
			comment.Translates.Add(
				new AlarmResetCommentTranslate(
					new AlarmResetCommentTranslateId(Guid.NewGuid()),
					comment.Id,
					AlarmResetCommentValue.Create(translate.Value),
					AlarmResetCommentLanguage.Create(translate.Language)
				)
			);
		}

		_context.AlarmResetComments.Add(comment);
		await _context.SaveChangesAsync(cancellationToken);

		return Ok(
			new
			{
				id = comment.Id.Value,
				organizationId = comment.OrganizationId.Value,
				translates = comment
					.Translates.Select(t => new
					{
						id = t.Id.Value,
						value = t.Value.Value,
						language = t.Language.Value,
					})
					.ToList(),
			}
		);
	}

	[HttpGet(Name = "GetAlarmResetCommentList")]
	[Authorize(Roles = $"{Roles.Manager},{Roles.Watcher}")]
	[ProducesResponseType<TableDataResponseModel<GetCommentListResponse>>(StatusCodes.Status200OK)]
	public async Task<IActionResult> GetList(
		[FromQuery] Guid organizationId,
		CancellationToken cancellationToken
	)
	{
		var organizationIdValue = new OrganizationId(organizationId);

		var comments = await _context
			.AlarmResetComments.Include(x => x.Translates)
			.Where(x => x.OrganizationId == organizationIdValue)
			.ToListAsync(cancellationToken);
		var filtered = comments
			.Select(comment =>
			{
				return new GetCommentListResponse(
					comment.Id.Value,
					comment.OrganizationId.Value,
					comment
						.Translates.Select(t => new TranslateComment(
							t.Language.Value,
							t.Value.Value
						))
						.ToList()
				);
			})
			.ToList();

		return Ok(new { items = filtered, total = filtered.Count });
	}

	[HttpPut("{id:guid}", Name = "UpdateAlarmResetComment")]
	[Authorize(Roles = Roles.Manager)]
	[ProducesResponseType<UpdateRequest>(StatusCodes.Status200OK)]
	[ProducesResponseType(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Update(
		Guid id,
		[FromBody] UpdateRequest request,
		CancellationToken cancellationToken
	)
	{
		var commentId = new AlarmResetCommentId(id);

		var comment = await _context
			.AlarmResetComments.Include(x => x.Translates)
			.FirstOrDefaultAsync(x => x.Id == commentId, cancellationToken);

		if (comment == null)
			return NotFound();

		comment.Translates.Clear();

		foreach (var translate in request.Translates)
		{
			comment.Translates.Add(
				new AlarmResetCommentTranslate(
					new AlarmResetCommentTranslateId(Guid.NewGuid()),
					comment.Id,
					AlarmResetCommentValue.Create(translate.Value),
					AlarmResetCommentLanguage.Create(translate.Language)
				)
			);
		}

		await _context.SaveChangesAsync(cancellationToken);

		return Ok(
			new UpdateCommentResponse(
				comment.Id.Value,
				comment.OrganizationId.Value,
				comment
					.Translates.Select(t => new TranslateComment(t.Value.Value, t.Language.Value))
					.ToList()
			)
		);
	}

	[HttpDelete("{id:guid}", Name = "DeleteAlarmResetComment")]
	[Authorize(Roles = Roles.Manager)]
	[ProducesResponseType(StatusCodes.Status204NoContent)]
	[ProducesResponseType(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Delete(Guid id, CancellationToken cancellationToken)
	{
		var commentId = new AlarmResetCommentId(id);

		var comment = await _context
			.AlarmResetComments.Include(x => x.Translates)
			.FirstOrDefaultAsync(x => x.Id == commentId, cancellationToken);

		if (comment == null)
			return NotFound();

		_context.AlarmResetComments.Remove(comment);
		await _context.SaveChangesAsync(cancellationToken);

		return NoContent();
	}

	[HttpGet("{id:guid}", Name = "GetAlarmResetComment")]
	[Authorize(Roles = $"{Roles.Manager},{Roles.Watcher}")]
	[ProducesResponseType<GetCommentResponse>(StatusCodes.Status200OK)]
	[ProducesResponseType(StatusCodes.Status404NotFound)]
	public async Task<IActionResult> Get(Guid id, CancellationToken ct)
	{
		var commentId = new AlarmResetCommentId(id);

		var comment = await _context
			.AlarmResetComments.Include(x => x.Translates)
			.FirstOrDefaultAsync(x => x.Id == commentId, ct);

		if (comment == null)
			return NotFound();

		return Ok(
			new GetCommentResponse(
				comment.Id.Value,
				comment.OrganizationId.Value,
				comment
					.Translates.Select(t => new TranslateComment(t.Language.Value, t.Value.Value))
					.ToList()
			)
		);
	}
}
