#encoding: utf-8
class OauthController < ApplicationController
  include ApplicationHelper

  before_filter :user_setup
  before_filter :require_login, only: [:authorize]


  skip_before_filter :verify_authenticity_token, only: [:token]


  def index
    render 'oauth/index', layout: false
  end


  # 客户端申请认证的URI,包含以下参数:
  #
  # response_type:表示授权类型,必选项,此处的值固定为”code”
  # client_id:表示客户端的ID,必选项
  # redirect_uri:表示重定向URI,可选项
  # scope:表示申请的权限范围,可选项
  # state:表示客户端的当前状态,可以指定任意值(最好是随机字符串),认证服务器会原封不动地返回这个值,可防止CSRF攻击
  #
  # 这个页显示授权页,如果授权成功,返回redirect_uri+code
  #
  #
  # 服务器回应客户端的URI,包含以下参数:
  #
  # code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次, 否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
  # state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
  def authorize
    begin

      #参数检查
      raise "response_type只能为code" unless params["response_type"] == "code"
      raise "client_id为必传项" unless params["client_id"].present?
      raise "redirect_uri为必传项" unless params["redirect_uri"].present?


      config = OauthConfig.where(client_id: params["client_id"], redirect_uri: params["redirect_uri"]).first
      raise "client_id或redirect_uri不正确" unless config


      @data = params

      if params[:gen_code]
        ## 检查通过,生成code
        oauth = Oauth.create!(client_id: config.client_id,
                              client_secret: config.client_secret,
                              redirect_uri: config.redirect_uri,
                              user_id: User.current.id
        )
        code = oauth.gen_code

        redirect_to params["redirect_uri"] + "?code=#{code}&state=#{params[:state]}"
      else
        render 'oauth/authorize', :layout => 'forge'
      end

    rescue => e
      logger.error e
      render :text => e.message
    end

  end

  def test_callback
    # 申请 token
    #
    client_id = "88d893c5a345313e7b8c6fcf23d3d024ee08d5e41ce120c3448b6eea77d8de30"
    client_secret = "e9240cc5fc913741db5aea93f2986a8ea0631bb67f7c00e41e491b95d9619e64"
    redirect_uri = "http://localhost:3000/oauth/cb"
    url = "http://127.0.0.1:3000/oauth/token?grant_type=authorization_code&code=#{params['code']}&redirect_uri=#{redirect_uri}&client_id=#{client_id}&client_secret=#{client_secret}"

    render text: url
  end


  # 客户端向认证服务器申请令牌的HTTP请求,包含以下参数:
  #
  # grant_type:表示使用的授权模式,必选项,此处的值固定为”authorization_code”。
  # code:表示上一步获得的授权码,必选项。
  # redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
  # client_id:表示客户端ID,必选项。
  # client_secret: 表示客户端密钥,必选项。
  #
  #
  # 认证服务器核对了授权码和”重定向URI”,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
  #
  # 认证服务器发送的HTTP回复,包含以下内容:
  #
  # access_token:表示访问令牌,必选项。
  # token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
  # expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
  # refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
  # scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。
  def token
    begin
      res = {}
      if params[:grant_type] == 'authorization_code'

        raise "code必传" unless params["code"]
        raise "client_id必传" unless params["client_id"]
        raise "client_secret必传" unless params["client_secret"]

        raise "code错误或已超时" unless Oauth.code_valid?(params["code"])

        oauth = Oauth.auth_code(params["code"], params["client_id"], params["client_secret"])
        raise "认证不通过" unless oauth

        ## 生成 token
        #
        oauth.gen_token

        oauth.reload

        res = {
            access_token: oauth.access_token,
            token_type: 'bearer',
            expires_in: oauth.token_expires_in,
            refresh_token: oauth.refresh_token
        }

      end

      render json: res.to_json

    rescue => e
      logger.error e
      render text: e.message
    end
  end


  def get_userinfo
    user = Oauth.auth(params["access_token"])

    user_info = {}
    if user
      user_info = {
          token: user.id,
          login: user.login,
          avatar_url: "https://openi.org.cn/images/" + url_to_avatar(user),
          name: user.show_name,
          email: user.mail,
          allow: (user.login == "guange"||user.phone=='15607313899') ? 1 : 0
      }
    end

    render json: user_info.to_json
  end

  ####--Start-- 获取Openi的授权码,access_token,以及用户信息。为在openi登录的用户创建相关的educoder用户 ####
  IDENTITY_SITE = Redmine::Configuration['openi_domain']
  ROOT_URL = Redmine::Configuration['educoder_domain']
  DEFAULT_PASSWORD = 'a12345678'.freeze
  TOKEN_CALL_BACK = '/oauth/get_token_callback'.freeze
  USER_INFO = '/oauth/userinfo'.freeze

  def get_code
    # 从OpenI发过来的回调中获取授权码
    code = params[:code]

    # 利用授权码从OpenI这里获取access_token
    client = get_client(IDENTITY_SITE)
    redirect_uri = "#{ROOT_URL}#{TOKEN_CALL_BACK}"
    access_token_hash = client.auth_code.get_token(code, redirect_uri: redirect_uri).to_hash

    # 利用access_token获取OpenI的用户信息
    access_token = access_token_hash[:access_token]
    get_info_url = "#{IDENTITY_SITE}#{USER_INFO}?access_token=#{access_token}"
    response = HTTParty.get(get_info_url)
    body_json = JSON.parse response.body

    openi_user_id = body_json['token']
    avatar_url = body_json['avatar_url']
    login = body_json['login']
    name = body_json['name']
    email = body_json['email']

    # 根据获取的用户信息来查询数据库,如已经存在对应的Educoder用户,则直接访问用户要访问的实训页面,否则为其创建用户后再访问实训页面
    openi = Openi.find_by_login(login)
    unless openi
      ActiveRecord::Base.transaction do
        # 如果Educoder中已存在与该OpenI用户的邮箱相同的用户,则会直接跳转到登录educoder的登录页面
        existing_user = User.find_by_mail(email)
        break if existing_user.present? && email.present?

        user = User.new(lastname: name, mail: email, mail_notification: email)
        user.login = generate_login('m')
        user.password = DEFAULT_PASSWORD
        user.certification = 1
        user.save!

        UserExtensions.create!(user_id: user.id, school_id: School.first.id, identity: 4, gender: 0)

        openi = Openi.create!(user_id: user.id, openi_user_id: openi_user_id, avatar_url: avatar_url, login: login, name: name, email: email)
        openi.user = user
        openi.save!
      end
    end

    self.logged_user = openi.user if openi.present? && openi.user.present?
    original_url = params[:original_url]
    if User.current.logged?
      redirect_to original_url
    else
      redirect_to signin_path
    end
  end

  def get_token_callback
  end
  ####--End-- 获取Openi的授权码,access_token,以及用户信息。为在openi登录的用户创建相关的educoder用户 ####

  private
  # 为新创建的用户随机生成以m为前缀的用户名,m表示该用户是用邮箱注册
  def generate_login(login_pre)
    us = UsersService.new
    us.generate_user_login(login_pre)
  end

  def require_login
    require "base64"
    if !User.current.logged?
      redirect_to '/login?back_url64=' + Base64.urlsafe_encode64(request.original_url)
    end
  end

  include Trustie::Http

end