package com.ruoyi.web.modules.account.support;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysRoleMapper;
import com.ruoyi.web.modules.account.constant.PlatformAdminConstants;
import com.ruoyi.web.modules.account.dto.PlatformAdminCreateDTO;
import com.ruoyi.web.modules.account.dto.PlatformAdminUpdateDTO;
import com.ruoyi.web.modules.account.mapper.PlatformAdminMapper;
import com.ruoyi.web.modules.account.vo.PlatformAdminRoleOptionVO;
import com.ruoyi.web.modules.store.mapper.BizMerchantAccountMapper;

/**
 * 平台管理员：角色校验、安全规则
 */
@Component
public class PlatformAdminSupport
{
    @Autowired
    private PlatformAdminMapper platformAdminMapper;

    @Autowired
    private SysRoleMapper roleMapper;

    @Autowired
    private BizMerchantAccountMapper merchantAccountMapper;

    public List<String> listRoleKeys()
    {
        return Arrays.asList(PlatformAdminConstants.DEFAULT_LIST_ROLE_KEYS);
    }

    public List<String> assignableRoleKeys()
    {
        return Arrays.asList(PlatformAdminConstants.DEFAULT_ASSIGNABLE_ROLE_KEYS);
    }

    public String resolveAdminName(String nickName, String userName)
    {
        if (StringUtils.isNotEmpty(nickName))
        {
            return nickName;
        }
        return userName;
    }

    public void assertInListScope(Long userId)
    {
        if (userId == null || platformAdminMapper.existsInListScope(userId, listRoleKeys()) <= 0)
        {
            throw new ServiceException(PlatformAdminConstants.MSG_NOT_FOUND);
        }
    }

    public void validateCreate(PlatformAdminCreateDTO dto)
    {
        if (dto == null)
        {
            throw new ServiceException(PlatformAdminConstants.MSG_ADMIN_NAME_REQUIRED);
        }
        if (StringUtils.isEmpty(dto.getAdminName()))
        {
            throw new ServiceException(PlatformAdminConstants.MSG_ADMIN_NAME_REQUIRED);
        }
        if (StringUtils.isEmpty(dto.getUserName()))
        {
            throw new ServiceException(PlatformAdminConstants.MSG_USERNAME_REQUIRED);
        }
        if (StringUtils.isEmpty(dto.getPhonenumber()))
        {
            throw new ServiceException(PlatformAdminConstants.MSG_PHONE_REQUIRED);
        }
        if (!dto.getPhonenumber().matches("^1\\d{10}$"))
        {
            throw new ServiceException(PlatformAdminConstants.MSG_PHONE_INVALID);
        }
        if (StringUtils.isEmpty(dto.getPassword()))
        {
            throw new ServiceException(PlatformAdminConstants.MSG_PASSWORD_REQUIRED);
        }
        validateAssignableRoleIds(dto.getRoleIds());
    }

    public void validateUpdate(PlatformAdminUpdateDTO dto)
    {
        if (dto == null || dto.getUserId() == null)
        {
            throw new ServiceException(PlatformAdminConstants.MSG_NOT_FOUND);
        }
        if (StringUtils.isEmpty(dto.getAdminName()))
        {
            throw new ServiceException(PlatformAdminConstants.MSG_ADMIN_NAME_REQUIRED);
        }
        if (StringUtils.isEmpty(dto.getPhonenumber()))
        {
            throw new ServiceException(PlatformAdminConstants.MSG_PHONE_REQUIRED);
        }
        if (!dto.getPhonenumber().matches("^1\\d{10}$"))
        {
            throw new ServiceException(PlatformAdminConstants.MSG_PHONE_INVALID);
        }
        validateAssignableRoleIds(dto.getRoleIds());
    }

    public void validateAssignableRoleIds(Long[] roleIds)
    {
        if (roleIds == null || roleIds.length == 0)
        {
            throw new ServiceException(PlatformAdminConstants.MSG_SELECT_ROLE);
        }
        Set<String> allowed = new HashSet<>(assignableRoleKeys());
        for (Long roleId : roleIds)
        {
            if (roleId == null)
            {
                throw new ServiceException(PlatformAdminConstants.MSG_INVALID_ROLE);
            }
            SysRole role = roleMapper.selectRoleById(roleId);
            if (role == null || !"0".equals(role.getDelFlag()) || !"0".equals(role.getStatus())
                    || !allowed.contains(role.getRoleKey()))
            {
                throw new ServiceException(PlatformAdminConstants.MSG_INVALID_ROLE);
            }
        }
    }

    public void assertEditableRoles(Long userId, Long[] platformRoleIds, Long currentUserId)
    {
        validateAssignableRoleIds(platformRoleIds);
        if (currentUserId != null && currentUserId.equals(userId))
        {
            if (platformRoleIds == null || platformRoleIds.length == 0)
            {
                throw new ServiceException(PlatformAdminConstants.MSG_CANNOT_REMOVE_ALL_PLATFORM_ROLES);
            }
        }
        assertKeepAtLeastOneAdmin(userId, platformRoleIds);
    }

    public void assertKeepAtLeastOneAdmin(Long userId, Long[] newPlatformRoleIds)
    {
        Long adminRoleId = resolveRoleIdByKey(PlatformAdminConstants.ADMIN_ROLE_KEY);
        boolean newHasAdmin = containsRoleId(newPlatformRoleIds, adminRoleId);
        if (platformAdminMapper.userHasRoleKey(userId, PlatformAdminConstants.ADMIN_ROLE_KEY) <= 0)
        {
            return;
        }
        int adminCount = platformAdminMapper.countUsersWithRoleKey(PlatformAdminConstants.ADMIN_ROLE_KEY);
        if (adminCount > 1)
        {
            return;
        }
        if (!newHasAdmin)
        {
            throw new ServiceException(PlatformAdminConstants.MSG_KEEP_ONE_ADMIN);
        }
    }

    public Long[] mergeRoleIdsOnUpdate(Long userId, Long[] newPlatformRoleIds)
    {
        Set<Long> merged = new HashSet<>();
        Set<String> assignable = new HashSet<>(assignableRoleKeys());
        for (PlatformAdminRoleOptionVO role : platformAdminMapper.selectAllRolesByUserId(userId))
        {
            if (role.getRoleKey() != null && !assignable.contains(role.getRoleKey()))
            {
                merged.add(role.getRoleId());
            }
        }
        if (newPlatformRoleIds != null)
        {
            merged.addAll(Arrays.asList(newPlatformRoleIds));
        }
        return merged.toArray(new Long[0]);
    }

    public void assertDeletable(Long[] userIds, Long currentUserId, List<SysUser> usersToDelete)
    {
        if (userIds == null || userIds.length == 0)
        {
            throw new ServiceException(PlatformAdminConstants.MSG_NOT_FOUND);
        }
        for (Long userId : userIds)
        {
            if (userId == null)
            {
                continue;
            }
            if (currentUserId != null && currentUserId.equals(userId))
            {
                throw new ServiceException(PlatformAdminConstants.MSG_CANNOT_DELETE_SELF);
            }
            if (SecurityUtils.isAdmin(userId))
            {
                throw new ServiceException(PlatformAdminConstants.MSG_CANNOT_DELETE_BUILTIN_ADMIN);
            }
            assertInListScope(userId);
        }
        int adminAmong = platformAdminMapper.countUsersWithRoleKeyAmong(
                PlatformAdminConstants.ADMIN_ROLE_KEY, userIds);
        int adminTotal = platformAdminMapper.countUsersWithRoleKey(PlatformAdminConstants.ADMIN_ROLE_KEY);
        if (adminTotal - adminAmong < 1)
        {
            throw new ServiceException(PlatformAdminConstants.MSG_KEEP_ONE_ADMIN);
        }
        for (SysUser user : usersToDelete)
        {
            if (user != null && merchantAccountMapper.countByAccountId(user.getUserId()) > 0)
            {
                throw new ServiceException(PlatformAdminConstants.MSG_MERCHANT_ACCOUNT_BOUND);
            }
        }
    }

    private Long resolveRoleIdByKey(String roleKey)
    {
        SysRole query = new SysRole();
        query.setRoleKey(roleKey);
        List<SysRole> roles = roleMapper.selectRoleList(query);
        for (SysRole role : roles)
        {
            if (roleKey.equals(role.getRoleKey()))
            {
                return role.getRoleId();
            }
        }
        return null;
    }

    private boolean containsRoleId(Long[] roleIds, Long roleId)
    {
        if (roleId == null || roleIds == null)
        {
            return false;
        }
        for (Long id : roleIds)
        {
            if (roleId.equals(id))
            {
                return true;
            }
        }
        return false;
    }

    public Long[] toPlatformRoleIdArray(List<PlatformAdminRoleOptionVO> roles)
    {
        if (roles == null || roles.isEmpty())
        {
            return new Long[0];
        }
        List<Long> ids = new ArrayList<>();
        for (PlatformAdminRoleOptionVO role : roles)
        {
            ids.add(role.getRoleId());
        }
        return ids.toArray(new Long[0]);
    }
}
