namespace MyOffice.Web.Controllers;

using AutoMapper;
using Core;
using Core.Extensions;
using Infrastructure.Attributes;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Models.Currency;
using Services.Currency;
using Services.Currency.Domain;

[Authorize]
[ApiController]
[Route("api/settings/currencies")]
[DefaultFromBody]
public class SettingCurrencyController : BaseApiController
{
	private readonly CurrencyService _currencyService;
	private readonly ILogger<SettingCurrencyController> _logger;
	private readonly IMapper _mapper;

	public SettingCurrencyController(
		CurrencyService currencyService,
		ILogger<SettingCurrencyController> logger,
		IMapper mapper
	)
	{
		_currencyService = currencyService;
		_logger = logger;
		_mapper = mapper;
	}

	[HttpGet]
	public async Task<ObjectResult> Get(CancellationToken cancellationToken)
	{
		var list = await _currencyService.GetAllWithRatesAsync(UserId, cancellationToken);

		return OkResponse(_mapper.Map<List<CurrencyViewModel>>(list).OrderBy(x => x.Id));
	}

	[HttpPost]
	public async Task<ObjectResult> Add(CurrencyAddModel currency, CancellationToken cancellationToken)
	{
		var exec = await _currencyService.CurrencyAddAsync(UserId, new CurrencyDto
		{
			UserId = UserId,
			CurrencyGlobalId = currency.Id,
			Name = currency.Name,
			ShortName = currency.ShortName,
		}, cancellationToken);

		switch (exec.Status)
		{
			case CurrencyAddStatus.success:
			case CurrencyAddStatus.exists:
				await _currencyService.CurrencyRateAddAsync(UserId, exec.Result!.Id, new CurrencyRateDto
				{
					CurrencyId = exec.Result!.Id,
					Rate = currency.Rate,
					Quantity = currency.Quantity,
					DateTime = currency.RateDate.Date,
				}, cancellationToken);
				return OkResponse(_mapper.Map<CurrencyViewModel>(exec.Result!));

			case CurrencyAddStatus.failed:
				return ProblemBadResponse("Adding currency failed.");

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

	[HttpPut("{id}")]
	public async Task<ObjectResult> Update(string id, CurrencyEditModel currency, CancellationToken cancellationToken)
	{
		var exec = await _currencyService.CurrencyUpdateAsync(
			UserId,
			id.AsGuid(),
			new CurrencyEdit { Name = currency.Name, ShortName = currency.ShortName, IsPrimary = currency.IsPrimary },
			cancellationToken
		);

		switch (exec.Status)
		{
			case CurrencyEditStatus.success:
				return OkResponse(_mapper.Map<CurrencyViewModel>(exec.Result!));

			case CurrencyEditStatus.not_found:
			case CurrencyEditStatus.failed:
				return ProblemNotFoundResponse("Currency not found.");

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

	[HttpDelete("{id}")]
	public async Task<ObjectResult> Delete([AsGuid] string id, CancellationToken cancellationToken)
	{
		var exec = await _currencyService.RemoveAsync(UserId, id.AsGuid(), cancellationToken);

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

			case GeneralExecStatus.not_found:
			case GeneralExecStatus.failure:
				return ProblemNotFoundResponse("Currency not found.");

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

	[HttpPost("{id}/rate")]
	public async Task<ObjectResult> AddRate(string id, CurrencyRateModel currencyRate, CancellationToken cancellationToken)
	{
		var exec = await _currencyService.CurrencyRateAddAsync(UserId, id.AsGuid(), new CurrencyRateDto
		{
			CurrencyId = id.AsGuid(),
			Quantity = currencyRate.Quantity,
			Rate = currencyRate.Rate,
			DateTime = currencyRate.RateDate.Date,
		}, cancellationToken);

		switch (exec.Status)
		{
			case CurrencyAddRateStatus.failed:
				return ProblemBadResponse("Adding currency rate failed.");
			case CurrencyAddRateStatus.not_found:
				return ProblemNotFoundResponse("Currency not found.");

			case CurrencyAddRateStatus.success:
				return OkResponse(_mapper.Map<CurrencyRateViewModel>(exec.Result!));

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