using adas_core.Application.Exceptions;
using adas_core.Application.Services.Interfaces;
using adas_core.Authentication.Attributes;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.DTO;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.Masters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using MongoDB.Bson;

namespace adas_core.Controllers;

[Route("master-lists")]
[ApiController]
public class MasterListController(
    IMasterListServiceFactory serviceFactory,
    ILogger<MasterListController> logger,
    IOptions<ListSettings> listSettings)
    : ControllerBase
{
    /// <summary>
    /// Retrieves the master list settings for the authenticated user with the required permission.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing the master list settings on success.</returns>
    [HttpGet("list-settings")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public IActionResult GetMasterListSettings()
    {
        return Ok(listSettings.Value);
    }

    /// <summary>
    /// Retrieves a master list for the specified type by resolving the appropriate service through the service factory and returning its full collection of records.
    /// </summary>
    /// <param name="typeName">The name of the master list type used to resolve the corresponding service.</param>
    /// <returns>An <see cref="IActionResult"/> containing the master list data when the specified type is valid.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> does not correspond to a valid <c>MasterListType</c> value.</exception>
    [HttpGet("{typeName}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetMasterList(string typeName)
    {
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        dynamic service = serviceFactory.GetService(masterListType);
        var result = await service.GetAllMasterList();
        return Ok(result);
    }


    /// <summary>
    /// Retrieves all master list entries (without their associated options) for every <see cref="MasterListType"/> value, aggregating the results from each type's dedicated service resolved through the service factory.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing an HTTP 200 response with the combined collection of <see cref="MasterListDto"/> items gathered from all master list services.</returns>
    [HttpGet("no-options")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetAllMasterListWithoutOptions()
    {
        List<MasterListDto> listToReturn = [];
        foreach (MasterListType listType in Enum.GetValues(typeof(MasterListType)))
        {
            dynamic service = serviceFactory.GetService(listType);
            listToReturn.AddRange(await service.GetAllMasterListWithoutOptions());
        }

        return Ok(listToReturn);
    }

    /// <summary>
    /// Retrieves a paginated master list of items for the specified master list type.
    /// Validates the <paramref name="typeName"/> against the <see cref="MasterListType"/> enumeration
    /// and resolves the appropriate service via the service factory to fetch the results.
    /// </summary>
    /// <param name="typeName">The name of the master list type to query, matched against the <see cref="MasterListType"/> enumeration.</param>
    /// <param name="request">The pagination filter containing paging criteria applied to the master list query.</param>
    /// <returns>An <see cref="IActionResult"/> containing the paginated master list result wrapped in an HTTP 200 OK response.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> cannot be parsed into a valid <see cref="MasterListType"/> value.</exception>
    [HttpPost("{typeName}/paginated-options")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetMasterListWithPaginatedOptions(string typeName,
            [FromBody] PaginationFilter request)
    {
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        dynamic service = serviceFactory.GetService(masterListType);
        var result = await service.GetAllMasterListWithPaginatedOptions(request);
        return Ok(result);
    }


    /// <summary>
    /// Retrieves the total count of master list items for a specified master list type.
    /// </summary>
    /// <param name="typeName">The name of the master list type to count, parsed into the <see cref="MasterListType"/> enum.</param>
    /// <returns>An <see cref="IActionResult"/> containing the count of master list items.</returns>
    /// <exception cref="BadRequestException">Thrown when the provided <paramref name="typeName"/> cannot be parsed into a valid <see cref="MasterListType"/>.</exception>
    [HttpGet("{typeName}/count")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetMasterListCount(string typeName)
    {
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        dynamic service = serviceFactory.GetService(masterListType);
        var result = await service.GetAllMasterListCount();
        return Ok(result);
    }

    /// <summary>
    /// Retrieves the record count for every <see cref="MasterListType"/> by resolving the corresponding service through the service factory and aggregating the results into a single dictionary.
    /// Requires the "AuthSome" role and the "DisplayId" permission on the "Source" resource.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing a <see cref="Dictionary{TKey, TValue}"/> that maps each <see cref="MasterListType"/> to its total record count, returned with HTTP 200 OK.</returns>
    [HttpGet("count")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetAllMasterListCounts()
    {
        var result = new Dictionary<MasterListType, int>();
        foreach (MasterListType listType in Enum.GetValues(typeof(MasterListType)))
        {
            dynamic service = serviceFactory.GetService(listType);
            result.Add(listType, await service.GetAllMasterListCount());
        }

        return Ok(result);
    }

    /// <summary>
    /// Retrieves a master list entry of the specified type by its unique identifier, delegating the lookup to the appropriate service resolved by the master list type.
    /// </summary>
    /// <param name="typeName">The name of the master list type used to resolve the corresponding service.</param>
    /// <param name="id">The unique identifier of the master list entry to retrieve.</param>
    /// <returns>An <see cref="IActionResult"/> containing the requested master list entry.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> cannot be parsed as a valid <c>MasterListType</c>.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="id"/> is not in a valid <c>ObjectId</c> format.</exception>
    [HttpGet("{typeName}/{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetMasterListById(string typeName, string id)
    {
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.GetMasterListById(masterListId);
        return Ok(result);
    }

    /// <summary>
    /// Retrieves paginated options for a master list entry by its type and identifier.
    /// Validates the type name against the supported <see cref="MasterListType"/> values and ensures the identifier is a valid ObjectId, delegating the actual retrieval to the appropriate service resolved through the service factory.
    /// </summary>
    /// <param name="typeName">The name of the master list type used to resolve the corresponding service.</param>
    /// <param name="id">The string representation of the master list identifier, which must be a valid ObjectId.</param>
    /// <param name="request">The pagination filter applied to the master list options query.</param>
    /// <returns>An <see cref="IActionResult"/> containing the paginated master list options returned by the resolved service.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> does not correspond to a valid <see cref="MasterListType"/> value.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="id"/> is not a valid ObjectId format.</exception>
    [HttpPost("{typeName}/{id}/master-list-paginated-options")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetMasterListByIdWithPaginatedOptions(string typeName, string id,
            [FromBody] PaginationFilter request)
    {
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        dynamic service = serviceFactory.GetService(masterListType);
        var result = await service.GetMasterListByIdWithPaginatedOptions(masterListId, request);
        return Ok(result);
    }

    /// <summary>
    /// Retrieves a paginated master list along with its associated paginated options for the specified master list type, applying both list and option filters.
    /// </summary>
    /// <param name="filters">The pagination pair DTO containing the list filter and option filter used to narrow the results.</param>
    /// <param name="typeName">The name of the master list type used to resolve the corresponding service through the service factory.</param>
    /// <returns>An <see cref="IActionResult"/> containing the paginated master list result with its options.</returns>
    /// <exception cref="BadRequestException">Thrown when the provided <paramref name="typeName"/> cannot be parsed as a valid <c>MasterListType</c>.</exception>
    [HttpPost("{typeName}/paginated-master-list-paginated-options")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetPaginatedMasterListWithPaginatedOptions([FromBody] PaginationPairDto filters,
            string typeName)
    {
        logger.LogDebug("Start GetPaginatedMasterList");
        var start = DateTime.Now;

        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.GetPaginatedMasterListWithPaginatedOptions(filters.ListFilter, filters.OptionFilter);

        var end = DateTime.Now;
        logger.LogDebug("Finished GetPaginatedMasterList in {TotalSeconds:F1} seconds", (end - start).TotalSeconds);
        return Ok(result);
    }


    /// <summary>
    /// Retrieves paginated options for a specified master list type and identifier, supporting role-based access and permission authorization.
    /// </summary>
    /// <param name="typeName">The name of the master list type to resolve from <see cref="MasterListType"/>.</param>
    /// <param name="id">The identifier of the master list used to scope the paginated options.</param>
    /// <param name="request">The pagination filter applied to the requested options.</param>
    /// <returns>An <see cref="IActionResult"/> containing the paginated options payload.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> cannot be parsed as a valid <see cref="MasterListType"/> value.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="id"/> is not a valid <see cref="ObjectId"/> format.</exception>
    [HttpPost("{typeName}/{id}/paginated-options")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetPaginatedOptions(string typeName, string id,
            [FromBody] PaginationFilter request)
    {
        logger.LogDebug("Start GetPaginatedOptions");
        var start = DateTime.Now;
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.GetPaginatedOptions(request, masterListId);

        var end = DateTime.Now;
        logger.LogDebug("Finished GetPaginatedOptions from list {id} in {TotalSeconds:F1} seconds", id,
            (end - start).TotalSeconds);

        return Ok(result);
    }

    /// <summary>
    /// Retrieves the master list options names for a specific master list entry, identified by its type and ID.
    /// Validates that the provided type name corresponds to a known <see cref="MasterListType"/> and that the ID is a valid <see cref="ObjectId"/>, delegating the lookup to the service resolved for the matching master list type.
    /// </summary>
    /// <param name="typeName">The name of the master list type used to resolve the appropriate service.</param>
    /// <param name="id">The identifier of the master list entry whose options names should be retrieved.</param>
    /// <returns>An <see cref="IActionResult"/> containing the master list options names returned by the resolved service.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> cannot be parsed as a <see cref="MasterListType"/> value.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="id"/> is not a valid <see cref="ObjectId"/> format.</exception>
    [HttpGet("{typeName}/{id}/master-list-options-names")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetMasterListOptionsNamesById(string typeName, string id)
    {
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        dynamic service = serviceFactory.GetService(masterListType);
        var result = await service.GetMasterListOptionsNamesById(masterListId);
        return Ok(result);
    }


    /// <summary>
    /// Retrieves a master list entry by its name, resolving the appropriate service based on the provided type.
    /// Validates that the type name maps to a known <see cref="MasterListType"/>; otherwise returns a bad request.
    /// </summary>
    /// <param name="typeName">The string representation of the <see cref="MasterListType"/> used to resolve the backing service.</param>
    /// <param name="name">The name of the master list entry to look up.</param>
    /// <returns>An <see cref="IActionResult"/> containing the result of the master list lookup.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> cannot be parsed into a valid <see cref="MasterListType"/>.</exception>
    [HttpGet("{typeName}/{name}/name")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetMasterListByName(string typeName, string name)
    {
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);
        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.GetMasterListByName(name);

        return Ok(result);
    }

    /// <summary>
    /// Retrieves the related options master list associated with a given source list.
    /// Validates that the provided type names map to valid <see cref="MasterListType"/> values and that the list identifier is a valid ObjectId; resolves the related list id through the source list service and returns the corresponding master list for the default locale.
    /// </summary>
    /// <param name="typeName">The name of the source <see cref="MasterListType"/> used to resolve the originating service.</param>
    /// <param name="listId">The identifier of the source master list from which the related list is resolved.</param>
    /// <param name="targetCategory">The name of the target <see cref="MasterListType"/> used to resolve the related options service.</param>
    /// <returns>The <see cref="MasterList"/> containing the related options for the requested category.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> or <paramref name="targetCategory"/> cannot be parsed as a valid <see cref="MasterListType"/>, or when <paramref name="listId"/> is not a valid ObjectId.</exception>
    [HttpGet("{typeName}/{listId}/related-options/{targetCategory}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetOptionTypeList(string typeName, string listId, string targetCategory)
    {
        if (!Enum.TryParse(typeName, out MasterListType masterListType1) ||
            !Enum.TryParse(targetCategory, out MasterListType masterListType2))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(listId, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        dynamic service1 = serviceFactory.GetService(masterListType1);

        ObjectId requestedListId = await service1.GetAssociatedList(masterListId, masterListType1, masterListType2);
        dynamic service2 = serviceFactory.GetService(masterListType2);

        MasterList options = await service2.GetMasterListById(requestedListId, LocaleEnum.Default);
        return Ok(options);
    }


    /// <summary>
    ///     Busca las opciones que contengan un texto de una lista determinada
    /// </summary>
    /// <param name="typeName">Tipo de Lista</param>
    /// <param name="id">id de la lista</param>
    /// <param name="searchOptions"></param>
    /// <returns></returns>
    [HttpPost("{typeName}/{id}/options")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetMasterListByIdAndSearchOptions(string typeName, string id,
        [FromBody] FilterOptionListElement searchOptions)
    {
        logger.LogDebug("Start GetMasterListByIdAndSearchOptions");
        var start = DateTime.Now;
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.GetMasterListByIdAndSearchOptions(masterListId, searchOptions);

        var end = DateTime.Now;
        logger.LogDebug("Finished GetMasterListByIdAndSearchOptions in {TotalSeconds:F1} seconds",
            (end - start).TotalSeconds);

        return Ok(result);
    }

    /// <summary>
    /// Retrieves a master list filtered by a text search term, selecting the appropriate service implementation based on the specified master list type.
    /// Validates that the type name corresponds to a known <see cref="MasterListType"/> and that the search text meets the minimum length requirement.
    /// </summary>
    /// <param name="typeName">The name of the master list type used to resolve the corresponding service via the service factory.</param>
    /// <param name="textSearch">The text used to filter the master list entries. Must be at least 3 characters long.</param>
    /// <returns>An <see cref="IActionResult"/> containing the filtered master list results returned by the resolved service.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> cannot be parsed to a valid <see cref="MasterListType"/> value.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="textSearch"/> is provided but is shorter than 3 characters.</exception>
    [HttpGet("{typeName}/{textSearch}/text")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetMasterListByTextSearch(string typeName, string? textSearch)
    {
        logger.LogDebug("Start GetMasterListByTextSearch");
        var start = DateTime.Now;

        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (textSearch is { Length: < 3 })
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectLength);
        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.GetMasterListByTextSearch(textSearch);
        var end = DateTime.Now;
        logger.LogDebug("Finished GetMasterListByTextSearch in {TotalSeconds:F1} seconds", (end - start).TotalSeconds);

        return Ok(result);
    }

    /// <summary>
    /// Retrieves a paginated master list of the specified type. Validates the <paramref name="typeName"/> against the <see cref="MasterListType"/> enumeration and dispatches the request to the corresponding service resolved through the service factory.
    /// </summary>
    /// <param name="request">The pagination filter containing paging criteria applied to the master list query.</param>
    /// <param name="typeName">The string identifier of the master list type, which is parsed into the <see cref="MasterListType"/> enum to resolve the appropriate service.</param>
    /// <returns>An <see cref="IActionResult"/> containing the paginated master list result.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> cannot be parsed into a valid <see cref="MasterListType"/> value.</exception>
    [HttpPost("{typeName}/paginated")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetPaginatedMasterList([FromBody] PaginationFilter request, string typeName)
    {
        logger.LogDebug("Start GetPaginatedMasterList");
        var start = DateTime.Now;

        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.GetPaginatedMasterList(request);
        var end = DateTime.Now;
        logger.LogDebug("Finished GetPaginatedMasterList in {TotalSeconds:F1} seconds", (end - start).TotalSeconds);
        return Ok(result);
    }


    /// <summary>
    /// Inserts a master list from the panel based on the specified master list type.
    /// Validates that the request body is provided and that the type name corresponds to a valid <see cref="MasterListType"/>.
    /// </summary>
    /// <param name="typeName">The name of the master list type used to resolve the target <see cref="MasterListType"/>.</param>
    /// <param name="master">The master list payload received from the request body.</param>
    /// <returns>An <see cref="IActionResult"/> containing the result of the insert operation.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="master"/> is null.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> cannot be parsed into a valid <see cref="MasterListType"/>.</exception>
    [HttpPost("{typeName}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> InsertMasterListFromPanel(string typeName, [FromBody] MasterList master)
    {
        if (master == null) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);
        var result = await serviceFactory.InsertMasterList(masterListType, master);
        return Ok(result);
    }

    /// <summary>
    /// Updates an existing master list entry identified by its type and identifier, replacing its contents with the supplied payload.
    /// </summary>
    /// <param name="typeName">The name of the master list type; must correspond to a value of <see cref="MasterListType"/>.</param>
    /// <param name="id">The identifier of the master list entry; must be a valid <see cref="ObjectId"/>.</param>
    /// <param name="master">The master list payload containing the new values to persist.</param>
    /// <returns>An <see cref="IActionResult"/> containing the result of the update operation.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="master"/> is <see langword="null"/>; when <paramref name="typeName"/> cannot be parsed into a <see cref="MasterListType"/>; or when <paramref name="id"/> is not a valid <see cref="ObjectId"/>.</exception>
    [HttpPut("{typeName}/{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateMasterList(string typeName, string id, [FromBody] MasterList master)
    {
        if (master == null) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);

        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        master.Id = masterListId;
        var result = await serviceFactory.UpdateMasterList(masterListType, master);
        return Ok(result);
    }

    /// <summary>
    /// Adds a filter option to a master list identified by its type name and id. Validates that the type name maps to a known master list type and that the id has a valid format before delegating the operation to the service resolved through the service factory.
    /// </summary>
    /// <param name="typeName">The name of the master list type used to resolve the appropriate service.</param>
    /// <param name="id">The string representation of the master list identifier.</param>
    /// <param name="opt">The filter option element to add to the master list, supplied in the request body.</param>
    /// <returns>An <see cref="IActionResult"/> containing the result of the add operation.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> cannot be parsed into a valid <c>MasterListType</c> value.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="id"/> is not a valid <c>ObjectId</c> format.</exception>
    [HttpPost("{typeName}/{id}/item")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> AddOptionToMasterList(string typeName, string id,
            [FromBody] FilterOptionListElement opt)
    {
        var start = DateTime.Now;
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.AddOptionToMasterList(masterListId, opt);

        var end = DateTime.Now;
        logger.LogDebug("Finished AddOptionToMasterList in {TotalSeconds:F1} seconds", (end - start).TotalSeconds);
        return Ok(result);
    }

    /// <summary>
    /// Updates an option within the specified master list, supporting multiple master list types and locales.
    /// </summary>
    /// <param name="locale">The locale identifier used to resolve the target language context.</param>
    /// <param name="typeName">The name of the master list type whose option should be updated.</param>
    /// <param name="id">The identifier of the master list entry to update.</param>
    /// <param name="opt">The option payload containing the updated values.</param>
    /// <returns>The updated master list result on success; otherwise, a 409 Conflict when the update fails.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> is not a valid <see cref="MasterListType"/>, when <paramref name="locale"/> is not a valid <see cref="LocaleEnum"/>, or when <paramref name="id"/> is not a valid ObjectId.</exception>
    [HttpPut("{locale}/{typeName}/{id}/item")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateOptionFromMasterList(string locale, string typeName, string id,
            [FromBody] OptionList opt)
    {
        var start = DateTime.Now;
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);
        if (!Enum.TryParse(locale, out LocaleEnum localeEnum))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.UpdateMasterListOption(masterListId, opt, typeName, localeEnum);

        var end = DateTime.Now;
        logger.LogDebug("Finished UpdateOptionToMasterList in {TotalSeconds:F1} seconds", (end - start).TotalSeconds);
        return result == null ? Conflict("Error while updating option in list") : (IActionResult)Ok(result);
    }

    /// <summary>
    /// Updates an option within a master list identified by its type and identifier from the administrative panel.
    /// </summary>
    /// <param name="typeName">The name of the master list type used to resolve the target service and operation.</param>
    /// <param name="id">The unique identifier of the master list entry to update.</param>
    /// <param name="opt">The option payload containing the values to apply to the master list entry.</param>
    /// <returns>An <see cref="IActionResult"/> that returns the updated result on success or a <c>Conflict</c> response when the update fails.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> does not match a valid <see cref="MasterListType"/> value.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="id"/> is not a valid <see cref="ObjectId"/> format.</exception>
    [HttpPut("{typeName}/{id}/item")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateOptionMasterListFromAdmPanel(string typeName, string id,
            [FromBody] OptionList opt)
    {
        var start = DateTime.Now;
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.UpdateMasterListOption(masterListId, opt, typeName);

        var end = DateTime.Now;
        logger.LogDebug("Finished UpdateOptionToMasterList in {TotalSeconds:F1} seconds", (end - start).TotalSeconds);
        return result == null ? Conflict("Error while updating option in list") : (IActionResult)Ok(result);
    }

    /// <summary>
    /// Updates the details of a master list option of the specified type, after validating the type and identifier.
    /// Returns a conflict response if the service cannot update the details, otherwise returns the updated result.
    /// </summary>
    /// <param name="typeName">The name of the master list type to update; must parse to a valid <see cref="MasterListType"/>.</param>
    /// <param name="id">The identifier of the master list entry to update; must be a valid ObjectId format.</param>
    /// <param name="opt">The payload containing the new details to apply to the master list entry.</param>
    /// <returns>The updated master list result wrapped in an <see cref="IActionResult"/>, or a conflict response when the update fails.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> does not correspond to a valid master list type, or when <paramref name="id"/> is not a valid ObjectId.</exception>
    [HttpPut("{typeName}/{id}/details")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateOptionDetailsFromMasterList(string typeName, string id,
            [FromBody] UpdateMasterListDetailsDto opt)
    {
        var start = DateTime.Now;
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.UpdateOptionDetailsToMasterList(masterListId, opt);

        var end = DateTime.Now;
        logger.LogDebug("Finished UpdateOptionToMasterList in {TotalSeconds:F1} seconds", (end - start).TotalSeconds);
        return result == null ? Conflict("Error while updating list details") : (IActionResult)Ok(result);
    }

    /// <summary>
    /// Updates the name of a master list of the specified type and identifier, enforcing role-based and
    /// "Source"/"DisplayId" permissions. Validates the master list type, the object id format, and the
    /// presence of a new name; returns 409 Conflict when the underlying update fails.
    /// </summary>
    /// <param name="typeName">The name of the master list type to update; must map to a <see cref="MasterListType"/> value.</param>
    /// <param name="id">The identifier of the master list to rename; must be a valid ObjectId.</param>
    /// <param name="udpateListNameAndDescriptionDto">The payload containing the new name to apply to the master list.</param>
    /// <returns>An <see cref="IActionResult"/> with the result of the update, <see cref="BadRequestResult"/> when the name is missing, or <see cref="ConflictObjectResult"/> when the update fails.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> does not correspond to a known master list type, or when <paramref name="id"/> is not a valid ObjectId.</exception>
    [HttpPut("{typeName}/{id}/name")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateMasterListName(string typeName, string id,
            [FromBody] UpdateListNameAndDescriptionDto udpateListNameAndDescriptionDto)
    {
        var start = DateTime.Now;
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        if (udpateListNameAndDescriptionDto.Name == null) return BadRequest($"Invalid name: {typeName}.");
        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.UpdateMasterListName(masterListId, udpateListNameAndDescriptionDto.Name);

        var end = DateTime.Now;
        logger.LogDebug("Finished UpdateMasterListName in {TotalSeconds:F1} seconds", (end - start).TotalSeconds);
        return !result ? Conflict("Error while updating list name") : (IActionResult)Ok(result);
    }

    /// <summary>
    /// Updates the description of a master list entry identified by its type and id. Validates that the type name maps to a known master list type, the id is a valid identifier, and the description is not null, then delegates the update to the appropriate service; returns a conflict response if the update fails.
    /// </summary>
    /// <param name="typeName">The name of the master list type used to resolve the appropriate service.</param>
    /// <param name="id">The identifier of the master list entry to update.</param>
    /// <param name="udpateListNameAndDescriptionDto">The DTO containing the new description to apply to the master list entry.</param>
    /// <returns>An <see cref="IActionResult"/> that returns OK on success, BadRequest when the description is null, or Conflict when the update does not succeed.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> does not correspond to a valid master list type.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="id"/> is not in a valid identifier format.</exception>
    [HttpPut("{typeName}/{id}/description")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateMasterListDescription(string typeName, string id,
            [FromBody] UpdateListNameAndDescriptionDto udpateListNameAndDescriptionDto)
    {
        var start = DateTime.Now;
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        if (udpateListNameAndDescriptionDto.Description == null) return BadRequest($"Description is null: {typeName}.");
        dynamic service = serviceFactory.GetService(masterListType);

        var result =
            await service.UpdateMasterListDescription(masterListId, udpateListNameAndDescriptionDto.Description);

        var end = DateTime.Now;
        logger.LogDebug("Finished UpdateMasterListDescription in {TotalSeconds:F1} seconds",
            (end - start).TotalSeconds);
        return !result ? Conflict("Error while updating list description") : (IActionResult)Ok(result);
    }


    /// <summary>
    /// Deletes a specific option from a master list, identified by its type, master list ID, and item ID.
    /// Validates that the type is a known master list type and that both the master list and item identifiers are valid ObjectId values.
    /// If the deletion produces no result, a conflict exception is thrown.
    /// </summary>
    /// <param name="typeName">The name of the master list type, used to resolve the appropriate service and parse to <see cref="MasterListType"/>.</param>
    /// <param name="id">The ObjectId of the master list containing the option to delete.</param>
    /// <param name="itemId">The ObjectId of the master list option to remove.</param>
    /// <returns>An <see cref="IActionResult"/> containing the result of the deletion operation.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> does not match a known master list type.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="id"/> or <paramref name="itemId"/> are not valid ObjectId values.</exception>
    /// <exception cref="ConflictException">Thrown when the deletion operation returns no result.</exception>
    [HttpDelete("{typeName}/{id}/item/{itemId}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> DeleteOptionFromMasterList(string typeName, string id, string itemId)
    {
        var start = DateTime.Now;
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        if (!ObjectId.TryParse(itemId, out var masterListItemId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        dynamic service = serviceFactory.GetService(masterListType);

        var result = await service.DeleteMasterListOption(masterListId, masterListItemId, typeName);

        var end = DateTime.Now;
        logger.LogDebug("Finished DeleteOptionToMasterList in {TotalSeconds:F1} seconds", (end - start).TotalSeconds);
        if (result == null) throw new ConflictException(HttpEnum.ErrorMessage.ConflictDeleteFailed);
        return Ok(result);
    }

    /// <summary>
    /// Deletes a master list item identified by its type name and identifier. Validates that the supplied type name maps to a known <see cref="MasterListType"/> and that the identifier is a valid ObjectId before delegating the deletion to the corresponding service.
    /// </summary>
    /// <param name="typeName">The name of the master list type used to resolve the appropriate service.</param>
    /// <param name="id">The string representation of the master list item's ObjectId to delete.</param>
    /// <returns>An <see cref="IActionResult"/> that returns <c>Ok</c> when the master list item is successfully deleted.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="typeName"/> cannot be parsed as a <see cref="MasterListType"/> value.</exception>
    /// <exception cref="BadRequestException">Thrown when <paramref name="id"/> is not a valid ObjectId format.</exception>
    [HttpDelete("{typeName}/{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> DeleteMasterList(string typeName, string id)
    {
        if (!Enum.TryParse(typeName, out MasterListType masterListType))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);

        if (!ObjectId.TryParse(id, out var masterListId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        dynamic service = serviceFactory.GetService(masterListType);

        await service.DeleteMasterListById(masterListId);
        return Ok();
    }
}