using Berufsschule_HAM.Services;
using Berufsschule_HAM.Models;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
using Microsoft.AspNetCore.Authorization;
using Novell.Directory.Ldap;
using Berufsschule_HAM.Helpers;

[Authorize(Roles = "CanManageLocations")]
[Route("[controller]")]
public class LocationsController : Controller
{
    private readonly LdapService _ldap;
    private readonly ILogger<LocationsController> _logger;

    public LocationsController(LdapService ldap, ILogger<LocationsController> logger)
    {
        _ldap = ldap;
        _logger = logger;
    }

    [HttpGet("GetAll")]
    public async Task<LocationsGetAllResponseModel> GetAll()
    {
        try
        {
            IEnumerable<LocationModel> list = await _ldap.ListLocationsAsync();
            return new LocationsGetAllResponseModel { Locations = list };
        }
        catch (Exception ex)
        {
            _logger.LogError("Unable to list locations: {Message} - {StackTrace}", ex.Message, ex.StackTrace);
            return new LocationsGetAllResponseModel { Locations = [] };
        }
    }

    [HttpPost("Create")]
    public async Task<LocationsCreateResponseModel> Create([FromBody]LocationsCreateRequestModel model)
    {
        try
        {
            LocationsDescription room = model.LocationsDescription;
            string location = StringHelpers.Slugify(room.Location + " " + room.RoomNumber + " " + room.Seat);
            LdapAttributeSet attributeSet =
            [
                new LdapAttribute("objectClass", "locality"),
                new LdapAttribute("objectClass", "top"),
                new LdapAttribute("l", location),
                new LdapAttribute("description", JsonSerializer.Serialize(room))
            ];

            await _ldap.CreateLocation(attributeSet);
            return new LocationsCreateResponseModel { Success = true };
        }
        catch (Exception ex)
        {
            _logger.LogError("Unable to create location: {Message} - {StackTrace}", ex.Message, ex.StackTrace);
            return new LocationsCreateResponseModel { Success = false, ErrorMessage = ex.Message };
        }
    }

    [HttpDelete("Delete")]
    public async Task<LocationsDeleteResponseModel> DeleteAsync(string cn)
    {
        if (cn is null)
        {
            _logger.LogError("Unable to delete location: cn parameter is null");
            return new(false, "cn parameter is null");
        }
        try
        {
            LocationModel location = await _ldap.GetLocationByCnAsync(cn);
            await SynchronizationHelper.SyncLocationName(_ldap, location.Location, "");
            await _ldap.DeleteLocationAsync(cn);
            return new(true);
        }
        catch (Exception ex)
        {
            _logger.LogError("Unable to delete location {Cn}: {Message} - {StackTrace}", cn, ex.Message, ex.StackTrace);
            return new(false, ex.Message);
        }
    }
    
    [HttpPost("Update")]
    public async Task<LocationsUpdateResponseModel> Update([FromBody]LocationsModifyRequestModel requestModel)
    {
        if (requestModel is null)
        {
            _logger.LogError("Unable to update a location because the LocationsModifyRequestModel is null");
            return new LocationsUpdateResponseModel { Success = false, ErrorMessage = "Request model is null" };
        }
        try
        {
            string location = requestModel.Location;
            LocationsDescription room = requestModel.Description;
            string newLocation = StringHelpers.Slugify(room.Location + " " + room.RoomNumber + " " + room.Seat); // TODO: fix DRY violation
            await SynchronizationHelper.SyncLocationName(_ldap, location, newLocation);
            await _ldap.UpdateLocation(location, "description", JsonSerializer.Serialize(room));
            await _ldap.UpdateLocation(location, "l", newLocation);
            return new LocationsUpdateResponseModel { Success = true };
        }
        catch (Exception ex)
        {
            _logger.LogError("Unable to update location {Location}: {Message} - {StackTrace}", requestModel?.Location ?? "unknown", ex.Message, ex.StackTrace);
            return new LocationsUpdateResponseModel { Success = false, ErrorMessage = ex.Message };
        }
    }
}
