package com.css.txw.sso.service.oauth2;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.nacos.shaded.com.google.common.annotations.VisibleForTesting;
import com.css.txw.sso.constants.ErrorCodeConstants;
import com.css.txw.sso.constants.RedisKeyConstants;
import com.css.txw.sso.mapper.oauth2.OAuth2ClientMapper;
import com.css.txw.sso.pojo.domain.oauth2.OAuth2ClientDO;
import com.css.ggzc.framework.common.exception.ServiceException;
import com.css.ggzc.framework.common.util.string.StrUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collection;

import static com.css.ggzc.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * OAuth2.0 Client Service 实现类
 */
@Service
@Validated
@Slf4j
public class OAuth2ClientServiceImpl implements OAuth2ClientService {

    @Resource
    private OAuth2ClientMapper oauth2ClientMapper;


    @VisibleForTesting
    void validateClientIdExists(String uuid, String clientId) {
        OAuth2ClientDO client = oauth2ClientMapper.selectByClientId(clientId);
        if (client == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的客户端
        if (uuid == null) {
            throw new ServiceException(ErrorCodeConstants.OAUTH2_CLIENT_EXISTS);
        }
        if (!client.getUuid().equals(uuid)) {
            throw exception(ErrorCodeConstants.OAUTH2_CLIENT_EXISTS);
        }
    }

    @Override
    @Cacheable(cacheNames = RedisKeyConstants.OAUTH_CLIENT, key = "#clientId",
            unless = "#result == null")
    public OAuth2ClientDO getOAuth2ClientFromCache(String clientId) {
        return oauth2ClientMapper.selectByClientId(clientId);
    }

    @Override
    public OAuth2ClientDO validOAuthClientFromCache(String clientId, String clientSecret, String authorizedGrantType,
                                                    Collection<String> scopes, String redirectUri) {
        // 校验客户端存在、且开启
        OAuth2ClientDO client = getSelf().getOAuth2ClientFromCache(clientId);
        if (client == null) {
            throw exception(ErrorCodeConstants.OAUTH2_CLIENT_NOT_EXISTS);
        }
        if (!"Y".equals(client.getYxbz())) {
            throw exception(ErrorCodeConstants.OAUTH2_CLIENT_DISABLE);
        }

        // 校验客户端密钥
        if (StrUtil.isNotEmpty(clientSecret) && ObjectUtil.notEqual(client.getSqmy(), clientSecret)) {
            throw exception(ErrorCodeConstants.OAUTH2_CLIENT_CLIENT_SECRET_ERROR);
        }

        // 校验回调地址
        if (StrUtil.isNotEmpty(redirectUri) && !StrUtils.startWithAny(redirectUri, Arrays.asList(client.getCdxdz().split(";")))) {
            throw exception(ErrorCodeConstants.OAUTH2_CLIENT_REDIRECT_URI_NOT_MATCH, redirectUri);
        }
        return client;
    }

    /**
     * 获得自身的代理对象，解决 AOP 生效问题
     *
     * @return 自己
     */
    private OAuth2ClientServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

}
