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

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

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

    [HttpGet("Get")]
    public async Task<GroupsGetResponseModel> GetAsync(GroupsIndexRequestModel model)
    {
        if (model is null)
        {
            return new GroupsGetResponseModel(
                successful: false,
                groupModels: null,
                exception: "Unable to create a group because the GroupsCreateRequestModel is null.");
        }
        try
        {
            
            string? cn = model.Cn;
            List<string> attributes = [.. _ldap.GroupsAttributes];
            if (!model.GidNumber) attributes.Remove("gidNumber");
            if (!model.Permissions) attributes.Remove("description");
            IEnumerable<GroupModel> groups;
            if (cn is null)
            {
                groups = await _ldap.ListGroupsAsync([.. attributes]);
            }
            else
            {
                try
                {
                    groups = [await _ldap.GetGroupByCnAsync(cn, [.. attributes])];
                }
                catch (InvalidOperationException)
                {
                    groups = [];
                }
            }
            return new(true, groups);
        } catch (Exception ex)
        {
            if (model.Cn is not null)
            {
                _logger.LogError("Unable to get group {model.Cn}: {ex.Message} - {ex.StackTrace}", [model.Cn, ex.Message, ex.StackTrace]);
            }
            else
            {
                _logger.LogError("Unable to get groups: {ex.Message} - {ex.StackTrace}", [ex.Message, ex.StackTrace]);
            }
            return new(false, null, ex.Message);
        }
    }

    [HttpDelete("Delete")]
    public async Task<GroupsDeleteResponseModel> Delete(string uid)
    {
        return await Task.Run(async () =>
        {
            try
            {
                await _ldap.DeleteGroupAsync(uid);
                return new GroupsDeleteResponseModel(true);
            }
            catch (Exception)
            {
                return new GroupsDeleteResponseModel(false);
            }
        });
    }

    [HttpPost("Create")]
    public async Task<GroupsCreateResponseModel> Create([FromBody]GroupsCreateRequestModel model)
    { 
        if (model is null)
        {
            return new GroupsCreateResponseModel(
                successful: false,
                exception: "Unable to create a group because the GroupsCreateRequestModel is null.");
        }
        try
        {
            List<GroupPermission> permissions = model.Permissions;
            string gidNumber = "0"; // TODO implement counter
            string cn = model.Cn;
            string displayName = model.DisplayName;

            LdapAttributeSet attributeSet =
            [
                new LdapAttribute("objectClass", "posixGroup"),
                new LdapAttribute("objectClass", "top"),
                new LdapAttribute("cn", cn),
                new LdapAttribute("gidNumber", gidNumber),
                new LdapAttribute(
                    "description",
                    JsonSerializer.Serialize(new GroupDescription(){DisplayName = displayName, Permissions = permissions}))
            ];
            
            await _ldap.CreateGroup(cn, attributeSet);
            return new(true);
        }
        catch (Exception ex)
        {
            _logger.LogError("Unable to create group: {ex.Message} - {ex.StackTrace}", [ex.Message, ex.StackTrace]);
            return new(false, ex.Message);
        }
    }
    
    [HttpPatch("Update")]
    public async Task<GroupsUpdateResponseModel> Update([FromBody]GroupsModifyRequestModel requestModel)
    {
        if (requestModel is null)
        {
            _logger.LogError("Unable to update a group because the GroupsModifyRequestModel is null");
            return new(false, "Unable to update a group because the GroupsModifyRequestModel is null");
        }
        string cn = requestModel.Cn;

        if (requestModel.NewCn is not null)
        {
            await _ldap.UpdateGroup(cn, "cn", requestModel.NewCn);
            cn = requestModel.NewCn;
        }
        if (requestModel.GidNumber is not null)
        {
            await _ldap.UpdateGroup(cn, "gidNumber", requestModel.GidNumber);
        }
        if (requestModel.Description is not null)
        {
            await _ldap.UpdateGroup(cn, "description", JsonSerializer.Serialize(requestModel.Description));
        }
        return new(true);
    }
}