namespace MyOffice.Web.Controllers;

using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

using Models.Item;
using Core.Extensions;
using Core;
using Infrastructure.Attributes;
using Services.Item;
using Services.Item.Domain;

[Authorize]
[ApiController]
[Route("api/settings")]
[DefaultFromBody]
public class SettingsItemController : BaseApiController
{
	private ILogger<SettingsItemController> _logger;
	private IMapper _mapper;
	private ItemService _itemService;

	public SettingsItemController(
		ILogger<SettingsItemController> logger,
		ItemService itemService,
		IMapper mapper
	)
	{
		_itemService = itemService;
		_logger = logger;
		_mapper = mapper;
	}

	[HttpGet("item-categories")]
	public async Task<ObjectResult> ItemsCategories(CancellationToken cancellationToken)
	{
		var list = await _itemService.GetAllCategoriesAsync(UserId, cancellationToken);

		return Ok(_mapper.Map<List<ItemCategoryViewModel>>(list)
			.OrderByDescending(x => x.SortOrder)
			.ThenBy(x => x.Name));
	}

	[HttpPost("item-categories")]
	public async Task<ObjectResult> ItemCategoriesAdd(ItemCategoryViewModel request, CancellationToken cancellationToken)
	{
		var exec = await _itemService.CategoryAddAsync(UserId, request.FromModel(), cancellationToken);

		switch (exec.Status)
		{
			case GeneralExecStatus.success:
				return Ok(_mapper.Map<ItemCategoryViewModel>(exec.Result!));

			case GeneralExecStatus.failure:
			case GeneralExecStatus.not_found:
				return ProblemBadResponse("Adding item category failed.");

			default:
				throw new NotSupportedException(exec.Status.ToString());
		}
	}

	[HttpPut("item-categories/{id}")]
	public async Task<ObjectResult> ItemCategoriesUpdate(
		[AsGuid] string id,
		ItemCategoryViewModel request,
		CancellationToken cancellationToken)
	{
		var exec = await _itemService.CategoryUpdateAsync(UserId, id.AsGuid(), request.FromModel(), cancellationToken);

		switch (exec.Status)
		{
			case GeneralExecStatus.success:
				return Ok(_mapper.Map<ItemCategoryViewModel>(exec.Result!));

			case GeneralExecStatus.failure:
			case GeneralExecStatus.not_found:
				return ProblemBadResponse("Update item category failed.");

			default:
				throw new NotSupportedException(exec.Status.ToString());
		}
	}

	[HttpDelete("item-categories/{id}")]
	public async Task<ObjectResult> ItemCategoriesDelete([AsGuid] string id, CancellationToken cancellationToken)
	{
		var exec = await _itemService.CategoryRemoveAsync(UserId, id.AsGuid(), cancellationToken);
		switch (exec.Status)
		{
			case ItemCategoryRemoveResult.success:
				return Ok(_mapper.Map<ItemCategoryViewModel>(exec.Result!));

			case ItemCategoryRemoveResult.failure:
				return ProblemBadResponse("Remove item category failed.");
			case ItemCategoryRemoveResult.not_found:
				return ProblemNotFoundResponse("Account item not found.");
			case ItemCategoryRemoveResult.accounts_exists:
				return ProblemBadResponse("Account motion have accounts.");

			default:
				throw new NotSupportedException(exec.Status.ToString());
		}
	}

	[HttpGet("items")]
	public async Task<ObjectResult> Items([FromQuery][AsGuid] string category, CancellationToken cancellationToken)
	{
		var categoryId = category.AsGuid();

		var list = categoryId != UserId
				? await _itemService.GetByCategoryAsync(UserId, categoryId, cancellationToken)
				: await _itemService.GetByUncategorizedAsync(UserId, cancellationToken);

		return Ok(_mapper.Map<List<ItemViewModel>>(list.OrderBy(x => x.Name)));
	}

	[HttpPut("items/{id}")]
	public async Task<ObjectResult> ItemsUpdate(
		[AsGuid] string id,
		ItemEditModel request,
		CancellationToken cancellationToken)
	{
		var exec = await _itemService.UpdateAsync(UserId, id.AsGuid(), request.Category.AsGuid(), cancellationToken);

		switch (exec.Status)
		{
			case GeneralExecStatus.not_found:
				return ProblemNotFoundResponse("Item not found.");
			case GeneralExecStatus.failure:
				return ProblemBadResponse("Item update failed.");
			case GeneralExecStatus.success:
				return Ok(_mapper.Map<ItemViewModel>(exec.Result!));

			default:
				throw new NotSupportedException(exec.Status.ToString());
		}
	}

	[HttpPost("items")]
	public async Task<ObjectResult> ItemsPost(ItemChangeCategoryModel request, CancellationToken cancellationToken)
	{
		var exec = await _itemService.UpdateItemsCategoryAsync(
			UserId,
			request.category.AsGuid(),
			request.Items.Select(x => x.AsGuid()).ToList(),
			cancellationToken);

		switch (exec)
		{
			case GeneralExecStatus.not_found:
				return ProblemNotFoundResponse("Category not found.");
			case GeneralExecStatus.failure:
				return ProblemBadResponse("Update failed.");
			case GeneralExecStatus.success:
				return Ok(new {});

			default:
				throw new NotSupportedException(exec.ToString());
		}
	}
}
