import { apiService } from "./api.service";
import oauthApi from "../constants/api/oauth.api";
import { RestfulResponse } from "../model/RestfulResponse";
import { OauthConfig } from "../model/OauthConfig";
import { tokenStore } from "../stores/token.store";
import { Token } from "../model/Token";
import { Code } from "../constants/enum/code.enum";
import Vue from "vue";
import { RestApi } from "../model/RestApi";
import { SyncCacheRequest } from "../model/SyncCacheRequest";
import { IdentityType } from "../constants/enum/identity-type.enum";
import { routeTopologyStore } from "../stores/route-topology.store";
import { userStore } from "../stores/user.store";
import sysUserInfoApi from "../constants/api/sys-user-info.api";
import { CoreConfig, SysUserInfo } from "../model";
import { urlUtilService } from "../services/url-util.service";
import { redirectUriStore } from "../stores/redirect-uri.store";

/**
 * @description: 授权服务
 * @author ChenRui
 * @date 2020/8/27 10:48
 */
class OauthService {
  isLogin = false; // 是否登录

  /**
   * @description: 全局配置-core
   * @author ChenRui
   * @date 2021/8/6 15:58
   */
  get coreConfig(): CoreConfig {
    if (Vue.prototype.$dc != null) {
      return Vue.prototype.$dc;
    }
    return new CoreConfig();
  }

  /**
   * @description: 全局配置-auth
   * @author ChenRui
   * @date 2021/8/6 15:59
   */
  get authConfig(): OauthConfig {
    if (this.coreConfig != null && this.coreConfig.oauth != null) {
      return this.coreConfig.oauth;
    }
    return new OauthConfig();
  }

  /**
   * @description: 检查登录状态并进行登录
   * @author ChenRui
   * @date 2021/8/4 10:52
   */
  checkAndLogin(): Promise<RestfulResponse> {
    if (!this.isLoadedToken) {
      // 判断用户是否登录
      const code = urlUtilService.getQueryValue("code");
      const state = urlUtilService.getQueryValue("state");
      if (code && state === this.authConfig.state) {
        // 在授权中心登录成功后重定向回用户页面，检查url是否包含授权码与自定义状态码,如果包含则使用授权码向授权服务器请求用户令牌
        return this.getTokenByAuthCode();
      } else {
        // 本地尚未存储令牌，同时当前url也未包含授权码，则导航到授权中心进行登录
        return this.login();
      }
    } else if (!this.isTokenExpiration) {
      // 判断用户令牌是否有效
      return this.refreshToken();
      // 若用户已经登录但令牌过期，此时需要使用refresh_token进行令牌刷新
    }
    return Promise.resolve(RestfulResponse.success(null, "用户已登录"));
  }

  /**
   * @description: 通过授权码获取令牌
   * @author ChenRui
   * @date 2021/8/4 11:53
   */
  getTokenByAuthCode(): Promise<RestfulResponse> {
    const query: any = {
      grant_type: "authorization_code",
      code: urlUtilService.getQueryValue("code"),
      redirect_uri: this.genRedirectUri(),
    };

    const basicAuth: any = this.genBasicAuth(); // 基础认证消息头

    const restApi: RestApi = new RestApi(oauthApi.token);
    restApi.url = this.authConfig.authorizeUrl + oauthApi.token.url;

    return apiService.general(restApi, query, undefined, basicAuth).then((res: any) => {
      if (res && res.access_token && res.jti) {
        tokenStore.token = res; // 缓存令牌信息
        return Promise.resolve(this.syncUserCache(res));
      } else {
        tokenStore.token = undefined; // 清空缓存的令牌信息
        userStore.user = undefined; // 清空用户信息
        return RestfulResponse.failure(res && res.msg ? res.msg : "令牌加载失败");
      }
    });
  }

  /**
   * @description: 单点登录
   * @author ChenRui
   * @date 2021/8/4 10:49
   */
  login(): Promise<RestfulResponse> {
    const authorizeUrl = this.authConfig.authorizeUrl + oauthApi.authorize.url;
    const param = {
      response_type: "code",
      client_id: this.authConfig.clientId,
      scope: this.authConfig.scope,
      state: this.authConfig.state,
      redirect_uri: this.genRedirectUri(),
    };
    window.location.href = apiService.urlQueryConvert(authorizeUrl, param);
    return Promise.resolve(RestfulResponse.failure("用户未登录，正在前往登录入口"));
  }

  /**
   * @description: 刷新令牌
   * @author ChenRui
   * @date 2021/8/4 17:57
   */
  refreshToken(): Promise<RestfulResponse> {
    const basicAuth: any = this.genBasicAuth(); // 基础认证消息头

    const restApi: RestApi = new RestApi(oauthApi.token);
    restApi.url = this.authConfig.authorizeUrl + oauthApi.token.url;
    const query: any = {
      grant_type: "refresh_token",
      refresh_token: tokenStore.token?.refresh_token,
    };
    return apiService.general(restApi, query, undefined, basicAuth).then((token: Token) => {
      if (token && token.access_token && token.jti) {
        tokenStore.token = token; // 缓存令牌信息
        return Promise.resolve(this.syncUserCache(token));
      } else {
        tokenStore.token = undefined; // 清空缓存的令牌信息
        userStore.user = undefined; // 清空用户信息
      }
      return RestfulResponse.failure("令牌刷新失败");
    });
  }

  /**
   * @description: 登出
   * @author ChenRui
   * @date 2020/12/18 17:53
   */
  logOut(authorizeUrl?: string): Promise<RestfulResponse> {
    // 清空服务器端的用户数据缓存
    if (userStore.user && userStore.user.userId) {
      const query = {
        userId: userStore.user.userId,
        userIdentity: tokenStore.token?.jti,
      };
      const restApi: RestApi = new RestApi(sysUserInfoApi.logout);
      restApi.url = this.coreConfig.baseApi + sysUserInfoApi.logout.url;
      return apiService
        .general(restApi, query)
        .then((response: RestfulResponse) => {
          return this.cleanOauthUserInfo();
        })
        .catch(() => {
          return this.cleanOauthUserInfo();
        });
    } else {
      return this.cleanOauthUserInfo();
    }
  }

  /**
   * @description: 生成重定向地址
   * @author ChenRui
   * @date 2021/8/6 17:36
   */
  genRedirectUri(isUseCache = true): string {
    if (this.authConfig.redirectUri) {
      return this.authConfig.redirectUri;
    } else {
      if (isUseCache && !!redirectUriStore.redirectUri) {
        return redirectUriStore.redirectUri;
      } else {
        const code = urlUtilService.getQueryValue("code");
        const state = urlUtilService.getQueryValue("state");
        if (code && state === this.authConfig.state) {
          const url = urlUtilService.deleteParameter(window.location.href, "code", "state");
          redirectUriStore.redirectUri = url;
        } else {
          redirectUriStore.redirectUri = window.location.href;
        }
      }
      return redirectUriStore.redirectUri;
    }
  }

  /**
   * @description: 清空授权中心缓存数据
   * @author ChenRui
   * @date 2021/8/6 18:20
   */
  private cleanOauthUserInfo(): Promise<RestfulResponse> {
    routeTopologyStore.inited = false; // 清空路由拓扑
    userStore.user = undefined;
    tokenStore.token = undefined;
    const restApi: RestApi = new RestApi(oauthApi.ssoLogout);
    restApi.url = this.authConfig.authorizeUrl + oauthApi.ssoLogout.url;
    setTimeout(() => {
      window.location.href = restApi.url + "?redirect_uri=" + this.genRedirectUri();
      redirectUriStore.redirectUri = undefined;
    }, 100);
    return Promise.resolve(RestfulResponse.success(null, "登出成功"));
  }

  /**
   * @description: 同步用户信息
   * @author ChenRui
   * @date 2021/8/4 21:23
   */
  private syncUserCache(token: Token): Promise<RestfulResponse> {
    const params: SyncCacheRequest = {
      userName: token.userName,
      userIdentity: token.jti,
      identityType: this.authConfig.identityType || IdentityType.password.code,
    };
    const restApi: RestApi = new RestApi(sysUserInfoApi.syncUserCache);
    restApi.url = this.coreConfig.baseApi + sysUserInfoApi.syncUserCache.url;

    return apiService.general(restApi, undefined, params).then((response: RestfulResponse) => {
      if (response.code === Code.SUCCESS.code) {
        userStore.user = response.data; // 缓存用户信息
      }
      return response;
    });
  }

  /**
   * @description: 创建基础认证消息头
   * @author ChenRui
   * @date 2021/8/4 21:18
   */
  private genBasicAuth(): any {
    const clientCredentials: string = this.authConfig.clientId + ":" + this.authConfig.clientSecret;
    const authorization = "Basic " + window.btoa(clientCredentials);
    const basicAuth: any = {
      Authorization: authorization,
    };
    return basicAuth;
  }

  /**
   * @description: 检查是否获加载完令牌
   * @author ChenRui
   * @date 2020/8/27 11:08
   */
  get isLoadedToken(): boolean {
    const token: Token | undefined = tokenStore.token;
    return token != null && !!token.access_token;
  }

  /**
   * @description: 检查是否获加载完令牌
   * @author ChenRui
   * @date 2021/8/6 23:36
   */
  get isLoadedUserInfo(): boolean {
    const sysUserInfo: SysUserInfo | undefined = userStore.user;
    return sysUserInfo != null && !!sysUserInfo.userId;
  }

  /**
   * @description: 检查令牌是否过期
   * @author ChenRui
   * @date 2021/8/4 11:13
   */
  get isTokenExpiration(): boolean {
    const token: Token | undefined = tokenStore.token;
    if (token != null && token.expires_in) {
      const currentTimeStamp = new Date().getTime();
      const expiratTimeStamp = Number(token.time) + Number((token.expires_in - 300) * 1000);
      return !(currentTimeStamp > expiratTimeStamp);
    }
    return false;
  }
}
const oauthService = new OauthService();
export { OauthService, oauthService };
