/*
 * Copyright 2020-2030 码匠君<herodotus@aliyun.com>
 *
 * Dante Engine licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Dante Engine 是 Dante Cloud 系统核心组件库，采用 APACHE LICENSE 2.0 开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1. 请不要删除和修改根目录下的LICENSE文件。
 * 2. 请不要删除和修改 Dante Engine 源码头部的版权声明。
 * 3. 请保留源码和相关描述文件的项目出处，作者声明等。
 * 4. 分发源码时候，请注明软件出处 <https://gitee.com/dromara/dante-cloud>
 * 5. 在修改包名，模块名称，项目代码等时，请注明软件出处 <https://gitee.com/dromara/dante-cloud>
 * 6. 若您的项目无法满足以上几点，可申请商业授权
 */

package org.dromara.dante.oauth2.commons.properties;

import com.google.common.base.MoreObjects;
import org.apache.commons.lang3.StringUtils;
import org.dromara.dante.core.constant.SymbolConstants;
import org.dromara.dante.core.constant.SystemConstants;
import org.dromara.dante.oauth2.commons.constant.OAuth2Constants;
import org.dromara.dante.oauth2.commons.enums.SasPersistence;
import org.dromara.dante.oauth2.commons.enums.SysPersistence;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;

import java.time.Duration;

/**
 * <p>Description: OAuth2 合规性配置参数 </p>
 *
 * @author : gengwei.zheng
 * @date : 2022/7/7 0:16
 */
@ConfigurationProperties(prefix = OAuth2Constants.PROPERTY_OAUTH2_AUTHENTICATION)
public class OAuth2AuthenticationProperties {

    /**
     * 授权确认页面地址
     */
    private String authorizationConsentUri = SystemConstants.OAUTH2_AUTHORIZATION_CONSENT_URI;

    /**
     * 设备码授权模式验证成功跳转地址
     */
    private String deviceVerificationSuccessUri = SystemConstants.OAUTH2_DEVICE_VERIFICATION_SUCCESS_URI;

    /**
     * 设备码授权模式验证失败跳转地址
     */
    private String deviceVerificationFailureUri = SystemConstants.OAUTH2_DEVICE_VERIFICATION_FAILURE_URI;


    /**
     * Ssl Bundle Provider 名称，该名称与 Spring SSL 配置匹配。
     */
    private String sslBundleProvider;
    /**
     * 开启登录失败限制
     */
    private SignInFailureLimited signInFailureLimited = new SignInFailureLimited();

    /**
     * 同一终端登录限制
     */
    private SignInEndpointLimited signInEndpointLimited = new SignInEndpointLimited();

    /**
     * 账户踢出限制
     */
    private SignInKickOutLimited signInKickOutLimited = new SignInKickOutLimited();

    private FormLogin formLogin = new FormLogin();

    /**
     * 核心数据持久化方式
     */
    private Persistence persistence = new Persistence();

    public String getAuthorizationConsentUri() {
        return authorizationConsentUri;
    }

    public void setAuthorizationConsentUri(String authorizationConsentUri) {
        this.authorizationConsentUri = authorizationConsentUri;
    }

    public String getDeviceVerificationSuccessUri() {
        return deviceVerificationSuccessUri;
    }

    public void setDeviceVerificationSuccessUri(String deviceVerificationSuccessUri) {
        this.deviceVerificationSuccessUri = deviceVerificationSuccessUri;
    }

    public String getDeviceVerificationFailureUri() {
        return deviceVerificationFailureUri;
    }

    public void setDeviceVerificationFailureUri(String deviceVerificationFailureUri) {
        this.deviceVerificationFailureUri = deviceVerificationFailureUri;
    }

    public String getSslBundleProvider() {
        return sslBundleProvider;
    }

    public void setSslBundleProvider(String sslBundleProvider) {
        this.sslBundleProvider = sslBundleProvider;
    }

    public SignInFailureLimited getSignInFailureLimited() {
        return signInFailureLimited;
    }

    public void setSignInFailureLimited(SignInFailureLimited signInFailureLimited) {
        this.signInFailureLimited = signInFailureLimited;
    }

    public SignInEndpointLimited getSignInEndpointLimited() {
        return signInEndpointLimited;
    }

    public void setSignInEndpointLimited(SignInEndpointLimited signInEndpointLimited) {
        this.signInEndpointLimited = signInEndpointLimited;
    }

    public SignInKickOutLimited getSignInKickOutLimited() {
        return signInKickOutLimited;
    }

    public void setSignInKickOutLimited(SignInKickOutLimited signInKickOutLimited) {
        this.signInKickOutLimited = signInKickOutLimited;
    }

    public FormLogin getFormLogin() {
        return formLogin;
    }

    public void setFormLogin(FormLogin formLogin) {
        this.formLogin = formLogin;
    }

    public Persistence getPersistence() {
        return persistence;
    }

    public void setPersistence(Persistence persistence) {
        this.persistence = persistence;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("authorizationConsentUri", authorizationConsentUri)
                .add("sslBundleProvider", sslBundleProvider)
                .add("signInFailureLimited", signInFailureLimited)
                .add("signInEndpointLimited", signInEndpointLimited)
                .add("signInKickOutLimited", signInKickOutLimited)
                .add("formLogin", formLogin)
                .toString();
    }

    public static class SignInFailureLimited {
        /**
         * 是否开启登录失败检测，默认开启
         */
        private Boolean enabled = true;

        /**
         * 允许允许最大失败次数
         */
        private Integer maxTimes = 5;

        /**
         * 是否自动解锁被锁定用户，默认开启
         */
        private Boolean autoUnlock = true;

        /**
         * 记录失败次数的缓存过期时间，默认：2小时。
         */
        private Duration expire = Duration.ofHours(2);

        public Boolean getEnabled() {
            return enabled;
        }

        public void setEnabled(Boolean enabled) {
            this.enabled = enabled;
        }

        public Integer getMaxTimes() {
            return maxTimes;
        }

        public void setMaxTimes(Integer maxTimes) {
            this.maxTimes = maxTimes;
        }

        public Duration getExpire() {
            return expire;
        }

        public void setExpire(Duration expire) {
            this.expire = expire;
        }

        public Boolean getAutoUnlock() {
            return autoUnlock;
        }

        public void setAutoUnlock(Boolean autoUnlock) {
            this.autoUnlock = autoUnlock;
        }

        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this)
                    .add("enabled", enabled)
                    .add("maxTimes", maxTimes)
                    .add("autoUnlock", autoUnlock)
                    .add("expire", expire)
                    .toString();
        }
    }

    public static class SignInEndpointLimited {
        /**
         * 同一终端登录限制是否开启，默认开启。
         */
        private Boolean enabled = false;

        /**
         * 统一终端，允许同时登录的最大数量
         */
        private Integer maximum = 1;

        public Boolean getEnabled() {
            return enabled;
        }

        public void setEnabled(Boolean enabled) {
            this.enabled = enabled;
        }

        public Integer getMaximum() {
            return maximum;
        }

        public void setMaximum(Integer maximum) {
            this.maximum = maximum;
        }

        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this)
                    .add("enabled", enabled)
                    .add("maximum", maximum)
                    .toString();
        }
    }

    public static class SignInKickOutLimited {
        /**
         * 是否开启 Session 踢出功能，默认开启
         */
        private Boolean enabled = true;

        public Boolean getEnabled() {
            return enabled;
        }

        public void setEnabled(Boolean enabled) {
            this.enabled = enabled;
        }

        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this)
                    .add("enabled", enabled)
                    .toString();
        }
    }

    public static class FormLogin {
        /**
         * UI 界面用户名标输入框 name 属性值
         */
        private String usernameParameter = UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY;
        /**
         * UI 界面密码标输入框 name 属性值
         */
        private String passwordParameter = UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_PASSWORD_KEY;
        /**
         * UI 界面Remember Me name 属性值
         */
        private String rememberMeParameter = AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY;
        /**
         * UI 界面验证码 name 属性值
         */
        private String captchaParameter = "captcha";
        /**
         * 登录页面地址
         */
        private String loginPageUrl = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL;
        /**
         * 登录失败重定向地址
         */
        private String failureUrl = loginPageUrl + SymbolConstants.QUESTION + DefaultLoginPageGeneratingFilter.ERROR_PARAMETER_NAME;
        /**
         * 表单登录认证地址
         */
        private String authenticationUrl;
        /**
         * 注销成功地址
         */
        private String logoutSuccessUrl = DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL + "?logout";
        /**
         * 自定义用户注册页面地址
         */
        private String registrationUrl;
        /**
         * 自定义忘记密码页面地址
         */
        private String forgotPasswordUrl;
        /**
         * 制定重定向时优先使用相对URI
         */
        private Boolean favorRelativeUris = Boolean.FALSE;
        /**
         * Cookie 有效期，默认：30天
         */
        private Duration cookieMaxAge = Duration.ofDays(30);
        /**
         * 验证码是否开启，默认 true，显示
         */
        private Boolean captchaEnabled = true;
        /**
         * 验证码类别，默认为 Hutool Gif 类型
         */
        private String category = "HUTOOL_GIF";

        public String getUsernameParameter() {
            return usernameParameter;
        }

        public void setUsernameParameter(String usernameParameter) {
            this.usernameParameter = usernameParameter;
        }

        public String getPasswordParameter() {
            return passwordParameter;
        }

        public void setPasswordParameter(String passwordParameter) {
            this.passwordParameter = passwordParameter;
        }

        public String getRememberMeParameter() {
            return rememberMeParameter;
        }

        public void setRememberMeParameter(String rememberMeParameter) {
            this.rememberMeParameter = rememberMeParameter;
        }

        public String getCaptchaParameter() {
            return captchaParameter;
        }

        public void setCaptchaParameter(String captchaParameter) {
            this.captchaParameter = captchaParameter;
        }

        public String getLoginPageUrl() {
            return loginPageUrl;
        }

        public void setLoginPageUrl(String loginPageUrl) {
            this.loginPageUrl = loginPageUrl;
        }

        public String getFailureUrl() {
            return failureUrl;
        }

        public void setFailureUrl(String failureUrl) {
            this.failureUrl = failureUrl;
        }

        public String getAuthenticationUrl() {
            return authenticationUrl;
        }

        public void setAuthenticationUrl(String authenticationUrl) {
            this.authenticationUrl = authenticationUrl;
        }

        public String getLogoutSuccessUrl() {
            return logoutSuccessUrl;
        }

        public void setLogoutSuccessUrl(String logoutSuccessUrl) {
            this.logoutSuccessUrl = logoutSuccessUrl;
        }

        public String getRegistrationUrl() {
            return registrationUrl;
        }

        public void setRegistrationUrl(String registrationUrl) {
            this.registrationUrl = registrationUrl;
        }

        public String getForgotPasswordUrl() {
            return forgotPasswordUrl;
        }

        public void setForgotPasswordUrl(String forgotPasswordUrl) {
            this.forgotPasswordUrl = forgotPasswordUrl;
        }

        public Boolean getFavorRelativeUris() {
            return favorRelativeUris;
        }

        public void setFavorRelativeUris(Boolean favorRelativeUris) {
            this.favorRelativeUris = favorRelativeUris;
        }

        public Duration getCookieMaxAge() {
            return cookieMaxAge;
        }

        public void setCookieMaxAge(Duration cookieMaxAge) {
            this.cookieMaxAge = cookieMaxAge;
        }

        public Boolean getCaptchaEnabled() {
            return captchaEnabled;
        }

        public void setCaptchaEnabled(Boolean captchaEnabled) {
            this.captchaEnabled = captchaEnabled;
        }

        public String getCategory() {
            return category;
        }

        public void setCategory(String category) {
            this.category = category;
        }

        public Boolean isRegistrationEnabled() {
            return StringUtils.isNotBlank(registrationUrl);
        }

        public Boolean isForgotPasswordEnabled() {
            return StringUtils.isNotBlank(forgotPasswordUrl);
        }

        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this)
                    .add("usernameParameter", usernameParameter)
                    .add("passwordParameter", passwordParameter)
                    .add("rememberMeParameter", rememberMeParameter)
                    .add("captchaParameter", captchaParameter)
                    .add("loginPageUrl", loginPageUrl)
                    .add("failureUrl", failureUrl)
                    .add("authenticationUrl", authenticationUrl)
                    .add("logoutSuccessUrl", logoutSuccessUrl)
                    .add("registrationUrl", registrationUrl)
                    .add("forgotPasswordUrl", forgotPasswordUrl)
                    .add("favorRelativeUris", favorRelativeUris)
                    .add("cookieMaxAge", cookieMaxAge)
                    .add("captchaEnabled", captchaEnabled)
                    .add("category", category)
                    .toString();
        }
    }

    public static class Persistence {

        /**
         * 是否初始化数据。
         */
        private Boolean initialized = Boolean.FALSE;
        /**
         * SAS 核心数据持久化方式
         */
        private SasPersistence sas = SasPersistence.JPA;
        /**
         * 系统核心数据持久化方式
         */
        private SysPersistence sys = SysPersistence.JPA;

        public Boolean getInitialized() {
            return initialized;
        }

        public void setInitialized(Boolean initialized) {
            this.initialized = initialized;
        }

        public SasPersistence getSas() {
            return sas;
        }

        public void setSas(SasPersistence sas) {
            this.sas = sas;
        }

        public SysPersistence getSys() {
            return sys;
        }

        public void setSys(SysPersistence sys) {
            this.sys = sys;
        }

        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this)
                    .add("initialized", initialized)
                    .add("sas", sas)
                    .add("sys", sys)
                    .toString();
        }
    }
}
