using Application.Abstractions.Identity;
using Application.Abstractions.Identity.Models;
using Microsoft.AspNetCore.Identity;
using System.Security.Claims;

namespace Infrastructure.Persistence.Identity
{
    public sealed class IdentityRoleWriter(RoleManager<IdentityRole> roleManager) : IIdentityRoleWriter
    {
        public async Task CreateRoleAsync(string roleName, CancellationToken ct)
        {
            var name = roleName?.Trim();

            if (string.IsNullOrWhiteSpace(name))
            {
                throw new InvalidOperationException("역할 이름은 필수입니다.");
            }

            if (name.Length > 256)
            {
                throw new InvalidOperationException("역할 이름은 256자를 초과할 수 없습니다.");
            }

            if (await roleManager.RoleExistsAsync(name))
            {
                throw new InvalidOperationException($"{name} 은 이미 존재합니다.");
            }

            var result = await roleManager.CreateAsync(new IdentityRole(name));

            if (!result.Succeeded)
            {
                throw new InvalidOperationException(string.Join(Environment.NewLine, result.Errors.Select(e => e.Description)));
            }
        }

        public async Task DeleteRoleAsync(string roleID, CancellationToken ct)
        {
            if (string.IsNullOrWhiteSpace(roleID))
            {
                throw new InvalidOperationException("Role ID는 필수입니다.");
            }

            var role = await roleManager.FindByIdAsync(roleID);
            if (role is null)
            {
                throw new InvalidOperationException("역할을 찾을 수 없습니다.");
            }

            var result = await roleManager.DeleteAsync(role);
            if (!result.Succeeded)
            {
                throw new InvalidOperationException(string.Join(Environment.NewLine, result.Errors.Select(e => e.Description)));
            }
        }

        public async Task UpdateRoleAsync(string roleID, PermissionDto permission, CancellationToken ct)
        {
            if (string.IsNullOrWhiteSpace(roleID))
            {
                throw new InvalidOperationException("Role ID는 필수입니다.");
            }

            var role = await roleManager.FindByIdAsync(roleID);
            if (role == null)
            {
                throw new InvalidOperationException("역할을 찾을 수 없습니다.");
            }

            // 기존 권한 제거
            var existingRoleClaims = await roleManager.GetClaimsAsync(role);
            foreach (var claim in existingRoleClaims.Where(c => c.Type == "Permission"))
            {
                var removed = await roleManager.RemoveClaimAsync(role, claim);
                if (!removed.Succeeded)
                {
                    throw new InvalidOperationException(string.Join(Environment.NewLine, removed.Errors.Select(e => e.Description)));
                }
            }

            // 선택된 권한 추출
            var selectedClaims = permission.RoleClaims.SelectMany(c => c.Permissions).Where(c => c.IsSelected).Select(c => c.DisplayValue).Where(v => !string.IsNullOrWhiteSpace(v)).ToList();
            if (selectedClaims is not null)
            {
                foreach (var value in selectedClaims)
                {
                    var added = await roleManager.AddClaimAsync(role, new Claim("Permission", value!));
                    if (!added.Succeeded)
                    {
                        throw new InvalidOperationException(string.Join(Environment.NewLine, added.Errors.Select(e => e.Description)));
                    }
                }
            }
        }
    }
}