namespace MyOffice.Web.Controllers;

using System.Security.Authentication;
using Microsoft.AspNetCore.Mvc;
using Core;
using Core.Extensions;
using IdentityModel;
using MyOffice.Web.Infrastructure.Attributes;
using MyOffice.Web.Models;

[DefaultFromBody]
public class BaseApiController : ControllerBase
{
	public Guid UserId
	{
		get
		{
			var subject = User.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.Subject)?.Value;
			if (subject.IsPresent() && Guid.TryParse(subject, out var guid)) return guid;

			throw new AuthenticationException("Get UserId failed");
		}
	}

	[NonAction]
	public ObjectResult ProblemBadResponse(string? detail = null)
	{
		return Problem(detail, statusCode: StatusCodes.Status400BadRequest);
	}

	[NonAction]
	public ObjectResult ProblemNotFoundResponse(string? detail = null)
	{
		return Problem(detail ?? "Not found.", statusCode: StatusCodes.Status404NotFound);
	}

	[NonAction]
	public ObjectResult ProblemForbiddenResponse(string? detail = null)
	{
		return Problem(detail ?? "Forbidden.", statusCode: StatusCodes.Status403Forbidden);
	}

	[NonAction]
	public ObjectResult OkResponse(IResponseModel response)
	{
		return Ok(response);
	}

	[NonAction]
	public ObjectResult OkResponse<T>(IEnumerable<T> response) where T : IResponseModel
	{
		return Ok(response);
	}

	/// <summary>
	/// Maps <see cref="GeneralExecStatus"/> to ProblemDetails status codes:
	/// not_found → 404, forbidden → 403, failure → 400.
	/// </summary>
	protected ObjectResult MapGeneralExec<T>(
		Exec<T, GeneralExecStatus> exec,
		Func<T, ObjectResult> onSuccess,
		string notFoundDetail,
		string? failureDetail = null,
		string? forbiddenDetail = null) where T : class
	{
		switch (exec.Status)
		{
			case GeneralExecStatus.success:
				return onSuccess(exec.Result!);
			case GeneralExecStatus.not_found:
				return ProblemNotFoundResponse(notFoundDetail);
			case GeneralExecStatus.forbidden:
				return ProblemForbiddenResponse(forbiddenDetail);
			case GeneralExecStatus.failure:
				return ProblemBadResponse(failureDetail ?? "Operation failed.");
			default:
				throw new NotSupportedException(exec.Status.ToString());
		}
	}
}