namespace MyOffice.Web.Controllers;

using AutoMapper;
using Core;
using Core.Extensions;
using Data.Models.Accounts;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Models.Account;
using Services.Account;
using Services.Account.Domain;

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class SettingsAccountController : BaseApiController
{
	private readonly ILogger<SettingsAccountController> _logger;
	private readonly IMapper _mapper;
	private readonly AccountService _accountService;

	public SettingsAccountController(
		ILogger<SettingsAccountController> logger,
		IMapper mapper,
		AccountService accountService
	)
	{
		_logger = logger;
		_mapper = mapper;
		_accountService = accountService;
	}

	[HttpGet("~/api/settings/account-categories")]
	public object AccountCategories()
	{
		var list = _accountService.GetAllCategories(UserId);

		return list.OrderBy(x => x.Name).Select(x => x.ToModel());
	}

	[HttpGet("~/api/settings/account-categories/{id}")]
	public object AccountCategory(string id)
	{
		var exec = _accountService.GetCategory(UserId, id.AsGuid());

		switch (exec.Status)
		{
			case GeneralExecStatus.not_found:
			case GeneralExecStatus.failure:
				return ProblemBadRequest("Account category not found.");

			case GeneralExecStatus.success:
				return exec.Result!.ToModel();

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

	[HttpPost("~/api/settings/account-categories")]
	public object AccountCategoriesAdd(AccountCategoryViewModel request)
	{
		var exec = _accountService.CategoryAdd(UserId, new AccountCategory { Name = request.Name! });
		switch (exec.Status)
		{
			case GeneralExecStatus.success:
				return exec.Result!;

			case GeneralExecStatus.failure:
			case GeneralExecStatus.not_found:
				return ProblemBadRequest("Adding account category failed.");

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

	[HttpPut("~/api/settings/account-categories/{id}")]
	public object AccountCategoriesEdit(string id, AccountCategoryViewModel request)
	{
		var exec = _accountService.CategoryUpdate(UserId, id.AsGuid(), new AccountCategory { Name = request.Name! });
		switch (exec.Status)
		{
			case GeneralExecStatus.success:
				return exec.Result!;

			case GeneralExecStatus.failure:
			case GeneralExecStatus.not_found:
				return ProblemBadRequest("Update account category failed.");

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

	[HttpDelete("~/api/settings/account-categories/{id}")]
	public object AccountCategoriesDelete(string id)
	{
		var exec = _accountService.CategoryRemove(UserId, id.AsGuid());
		switch (exec.Status)
		{
			case AccountCategoryRemoveResult.success:
				return exec.Result!;

			case AccountCategoryRemoveResult.failure:
				return ProblemBadRequest("Remove account category failed.");
			case AccountCategoryRemoveResult.not_found:
				return ProblemBadRequest("Account category not found.");
			case AccountCategoryRemoveResult.accounts_exists:
				return ProblemBadRequest("Account category have accounts.");

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

	[HttpGet("~/api/settings/accounts")]
	public List<AccountViewModel> AccountsGet(string? category)
	{
		var list = category.IsPresent()
			? _accountService.GetByCategory(UserId, category!.AsGuid())
			: _accountService.GetAllAccounts(UserId);

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

	[HttpPost("~/api/settings/accounts")]
	public object AccountsAdd(AccountViewModel request)
	{
		var exec = _accountService.AccountAdd(UserId, new AccountAdd
		{
			Name = request.Name,
			CurrencyId = request.CurrencyId,
			CategoryId = request.CategoryId.AsGuid(),
			Type = request.Type,
		});

		switch (exec.Status)
		{
			case AccountAddResult.category_not_found:
				return ProblemBadRequest("Category not found.");
			case AccountAddResult.currency_not_found:
				return ProblemBadRequest("Currency not found.");
			case AccountAddResult.failure:
				return ProblemBadRequest("Adding account failed.");
			case AccountAddResult.success:
				return exec.Result!;

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


	[HttpPut("~/api/settings/accounts/{id}")]
	public object AccountsAdd(string id, AccountEditRequestModel request)
	{
		var exec = _accountService.AccountUpdate(UserId, id.AsGuid(), new AccountEdit
		{
			Name = request.Name,
			CurrencyId = request.CurrencyId,
			CategoryId = request.CategoryId?.AsGuidNull(),
			UserId = request.UserId?.AsGuidNull(),
			Type = request.Type,
		});

		switch (exec.Status)
		{
			case AccountEditResult.not_found:
				return ProblemBadRequest("Account not found.");
			case AccountEditResult.category_not_found:
				return ProblemBadRequest("Category not found.");
			case AccountEditResult.currency_not_found:
				return ProblemBadRequest("Currency not found.");
			case AccountEditResult.failure:
				return ProblemBadRequest("Adding account failed.");
			case AccountEditResult.success:
				return exec.Result!;

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

	[HttpDelete("~/api/settings/accounts/{id}")]
	public object AccountsDelete(string id)
	{
		var exec = _accountService.AccountDelete(UserId, id);
		switch (exec.Status)
		{
			case GeneralExecStatus.not_found:
				return ProblemBadRequest("Account not found.");
			case GeneralExecStatus.success:
				return exec.Result!;

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

	[HttpDelete("~/api/settings/accounts/{id}/category/{categoryId}")]
	public object AccountsCategoryRemove(string id, string categoryId)
	{
		var exec = _accountService.AccountCategoryRemove(UserId, id.AsGuid(), categoryId.AsGuid());

		switch (exec.Status)
		{
			case GeneralExecStatus.not_found:
			case GeneralExecStatus.failure:
				return ProblemBadRequest("Category not found.");

			case GeneralExecStatus.success:
				return exec.Result!;

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