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

namespace OmsorgCore.Api.Controllers;

/// <summary>
/// Qualifikationsabhängige Verrechnungssätze sind eine 1:n-Unterressource von Facility (FR-EIN-4) —
/// kein eigenständiges Core-Objekt, daher unter /api/facilities/{facilityId}/qualification-rates und
/// mit den gleichen Facilities-Rechten gegated statt einem eigenen ModuleType (analog FacilityContact).
/// </summary>
[ApiController]
[Authorize]
[Route("api/facilities/{facilityId:guid}/qualification-rates")]
public class FacilityQualificationRatesController : ControllerBase
{
    private const string QualificationListKey = "Qualification";

    private readonly IFacilityService _facilityService;
    private readonly IFacilityQualificationRateService _facilityQualificationRateService;
    private readonly IValueListRepository _valueListRepository;

    public FacilityQualificationRatesController(
        IFacilityService facilityService,
        IFacilityQualificationRateService facilityQualificationRateService,
        IValueListRepository valueListRepository)
    {
        _facilityService = facilityService;
        _facilityQualificationRateService = facilityQualificationRateService;
        _valueListRepository = valueListRepository;
    }

    [HttpGet]
    [RequirePermission(ModuleType.Facilities, PermissionAction.View)]
    public async Task<ActionResult<IReadOnlyList<FacilityQualificationRateResponse>>> GetAll(Guid facilityId, CancellationToken cancellationToken)
    {
        if (await _facilityService.GetByIdAsync(facilityId, cancellationToken) is null)
        {
            return NotFound();
        }

        var rates = await _facilityQualificationRateService.GetByFacilityIdAsync(facilityId, cancellationToken);
        return Ok(rates.Select(ToResponse).ToList());
    }

    [HttpPost]
    [RequirePermission(ModuleType.Facilities, PermissionAction.Create)]
    public async Task<ActionResult<FacilityQualificationRateResponse>> Create(Guid facilityId, CreateFacilityQualificationRateRequest request, CancellationToken cancellationToken)
    {
        if (await _facilityService.GetByIdAsync(facilityId, cancellationToken) is null)
        {
            return NotFound();
        }

        var fieldError = await ValidateRequestAsync(request.Qualification, request.Rate, cancellationToken);
        if (fieldError is not null)
        {
            return BadRequest(fieldError);
        }

        var rate = new FacilityQualificationRate
        {
            FacilityId = facilityId,
            Qualification = request.Qualification,
            Rate = request.Rate
        };

        var created = await _facilityQualificationRateService.CreateAsync(rate, cancellationToken);
        return CreatedAtAction(nameof(GetAll), new { facilityId }, ToResponse(created));
    }

    [HttpPut("{id:guid}")]
    [RequirePermission(ModuleType.Facilities, PermissionAction.Edit)]
    public async Task<ActionResult<FacilityQualificationRateResponse>> Update(Guid facilityId, Guid id, UpdateFacilityQualificationRateRequest request, CancellationToken cancellationToken)
    {
        var existing = await _facilityQualificationRateService.GetByIdAsync(id, cancellationToken);
        if (existing is null || existing.FacilityId != facilityId)
        {
            return NotFound();
        }

        var fieldError = await ValidateRequestAsync(request.Qualification, request.Rate, cancellationToken);
        if (fieldError is not null)
        {
            return BadRequest(fieldError);
        }

        var updates = new FacilityQualificationRate
        {
            Qualification = request.Qualification,
            Rate = request.Rate
        };

        var updated = await _facilityQualificationRateService.UpdateAsync(id, updates, cancellationToken);
        return updated is null ? NotFound() : Ok(ToResponse(updated));
    }

    [HttpDelete("{id:guid}")]
    [RequirePermission(ModuleType.Facilities, PermissionAction.Delete)]
    public async Task<IActionResult> Delete(Guid facilityId, Guid id, CancellationToken cancellationToken)
    {
        var existing = await _facilityQualificationRateService.GetByIdAsync(id, cancellationToken);
        if (existing is null || existing.FacilityId != facilityId)
        {
            return NotFound();
        }

        var deleted = await _facilityQualificationRateService.DeleteAsync(id, cancellationToken);
        return deleted ? NoContent() : NotFound();
    }

    private async Task<string?> ValidateRequestAsync(string qualification, decimal rate, CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(qualification) || qualification.Length > 200)
        {
            return "Qualification ist erforderlich und darf maximal 200 Zeichen lang sein.";
        }

        var allowedQualifications = await _valueListRepository.GetActiveValuesAsync(QualificationListKey, cancellationToken);
        if (!allowedQualifications.Contains(qualification))
        {
            return $"Qualification muss einer der folgenden Werte sein: {string.Join(", ", allowedQualifications)}.";
        }

        if (rate < 0)
        {
            return "Rate darf nicht negativ sein.";
        }

        return null;
    }

    private static FacilityQualificationRateResponse ToResponse(FacilityQualificationRate rate)
        => new(
            rate.Id,
            rate.FacilityId,
            rate.Qualification,
            rate.Rate);
}
