using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using OmsorgCore.Api.Contracts;
using OmsorgCore.Api.Security;
using OmsorgCore.Application.Services;
using OmsorgCore.Domain.Entities;
using OmsorgCore.Domain.Enums;

namespace OmsorgCore.Api.Controllers;

/// <summary>
/// Verwaltet die konfigurierbaren Auswahllisten (Mitarbeiterstatus, Beschäftigungsart, CRM-Status,
/// Einrichtungstyp, Vertragstyp/-status, Auftragsstatus) — siehe omsorgCore/CLAUDE.md, Abschnitt
/// "Konfigurierbare Auswahllisten". Lesen ist für jeden eingeloggten Nutzer erlaubt (die aufrufenden
/// Formulare gehören zu unterschiedlichen Modulen), Schreiben ist eine eigene Admin-Funktion
/// (<see cref="ModuleType.Configuration"/>), getrennt von der Benutzer-/Rechteverwaltung.
/// </summary>
[ApiController]
[Authorize]
[Route("api/value-lists")]
public class ValueListsController : ControllerBase
{
    private readonly IValueListService _valueListService;

    public ValueListsController(IValueListService valueListService)
    {
        _valueListService = valueListService;
    }

    [HttpGet]
    public async Task<ActionResult<IReadOnlyList<ValueListResponse>>> GetLists(CancellationToken cancellationToken)
    {
        var lists = await _valueListService.GetListsAsync(cancellationToken);
        return Ok(lists.Select(l => new ValueListResponse(l.Id, l.Key, l.DisplayName)).ToList());
    }

    [HttpGet("{key}/items")]
    public async Task<ActionResult<IReadOnlyList<ValueListItemResponse>>> GetItems(string key, CancellationToken cancellationToken)
    {
        var items = await _valueListService.GetItemsAsync(key, cancellationToken);
        return Ok(items.Select(ToResponse).ToList());
    }

    [HttpPost("{key}/items")]
    [RequirePermission(ModuleType.Configuration, PermissionAction.Edit)]
    public async Task<ActionResult<ValueListItemResponse>> CreateItem(string key, CreateValueListItemRequest request, CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(request.Value) || request.Value.Length > 100)
        {
            return BadRequest("Value ist erforderlich und darf maximal 100 Zeichen lang sein.");
        }

        try
        {
            var item = await _valueListService.CreateItemAsync(
                key, request.Value, request.SortOrder, request.IsDefault, request.IsInitial, request.IsTerminal, request.TriggersFollowUp, cancellationToken);
            return Ok(ToResponse(item));
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(ex.Message);
        }
    }

    [HttpPut("{key}/items/{id:guid}")]
    [RequirePermission(ModuleType.Configuration, PermissionAction.Edit)]
    public async Task<ActionResult<ValueListItemResponse>> UpdateItem(string key, Guid id, UpdateValueListItemRequest request, CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(request.Value) || request.Value.Length > 100)
        {
            return BadRequest("Value ist erforderlich und darf maximal 100 Zeichen lang sein.");
        }

        var item = await _valueListService.UpdateItemAsync(
            id, request.Value, request.SortOrder, request.IsDefault, request.IsInitial, request.IsTerminal, request.TriggersFollowUp, cancellationToken);
        return item is null ? NotFound() : Ok(ToResponse(item));
    }

    [HttpDelete("{key}/items/{id:guid}")]
    [RequirePermission(ModuleType.Configuration, PermissionAction.Edit)]
    public async Task<IActionResult> DeleteItem(string key, Guid id, CancellationToken cancellationToken)
    {
        var result = await _valueListService.DeleteItemAsync(id, cancellationToken);
        if (result.Success)
        {
            return NoContent();
        }

        return result.FailureReason switch
        {
            DeleteValueListItemFailureReason.ItemNotFound => NotFound(),
            DeleteValueListItemFailureReason.InUse => Conflict(result.Usages
                .Select(u => new ValueListUsageResponse(u.EntityType, u.EntityId, u.DisplayLabel))
                .ToList()),
            _ => Conflict()
        };
    }

    [HttpGet("{key}/items/{id:guid}/usages")]
    [RequirePermission(ModuleType.Configuration, PermissionAction.Edit)]
    public async Task<ActionResult<IReadOnlyList<ValueListUsageResponse>>> GetUsages(string key, Guid id, CancellationToken cancellationToken)
    {
        var usages = await _valueListService.GetUsagesAsync(id, cancellationToken);
        return Ok(usages.Select(u => new ValueListUsageResponse(u.EntityType, u.EntityId, u.DisplayLabel)).ToList());
    }

    [HttpGet("{key}/transitions")]
    public async Task<ActionResult<IReadOnlyList<ValueListTransitionResponse>>> GetTransitions(string key, CancellationToken cancellationToken)
    {
        var transitions = await _valueListService.GetTransitionsAsync(key, cancellationToken);
        return Ok(transitions.Select(t => new ValueListTransitionResponse(t.Id, t.FromItemId, t.ToItemId, t.RequiresApproval)).ToList());
    }

    [HttpPut("{key}/transitions")]
    [RequirePermission(ModuleType.Configuration, PermissionAction.Edit)]
    public async Task<IActionResult> ReplaceTransitions(string key, List<ValueListTransitionRequest> request, CancellationToken cancellationToken)
    {
        await _valueListService.ReplaceTransitionsAsync(key, request.Select(t => (t.FromItemId, t.ToItemId)), cancellationToken);
        return NoContent();
    }

    private static ValueListItemResponse ToResponse(ValueListItem item)
        => new(item.Id, item.Value, item.SortOrder, item.IsDefault, item.IsInitial, item.IsTerminal, item.TriggersFollowUp);
}
