class SessionsController < ApplicationController
  before_action :setup_apple_client, only: [:apple_callback]

  def apple_callback
    return unprocessable_entity unless params[:code].present? && params[:identity_token].present?
    
    @client.authorization_code = params[:code]
    
    begin
      token_response = @client.access_token!
    rescue AppleID::Client::Error => e
      # puts e # gives useful messages from apple on failure
      return unauthorized
    end
    
    id_token_back_channel = token_response.id_token
    id_token_back_channel.verify!(
      client: @client
      access_token: token_response.access_token,
    )

    id_token_front_channel = AppleID::IdToken.decode(params[:identity_token])
    id_token_front_channel.verify!(
      client: @client,
      code: params[:code],
    )
    
    id_token = token_response.id_token
    
    # You may want to change the "find_by" method to a less time consuming method.
    # id_token.sub, a.k.a apple_uid is unique per user, no matter how many times you perform the same request.
    @user = User.find_by(apple_uid: id_token.sub)
    
    return sign_in_and_return if @user.present?
    
    @user = User.find_by_email(id_token.email)
    
    if @user.present
      # Enable apple login to existing user
      @user.update_column(:apple_uid, id_token.sub)
      return sign_in_and_return
    else
      @user = User.register_user_from_apple(id_token.sub, id_token.email)
      return created
    end
  end

  private
  def created
    render status: 201, json: {
        status: "success",
        data: @user
      }
  end

  def setup_apple_client
    @client ||= AppleID::Client.new(
      identifier: ENV['APPLE_CLIENT_ID'],
      team_id: ENV['APPLE_TEAM_ID'],
      key_id: ENV['APPLE_KEY'],
      private_key: OpenSSL::PKey::EC.new(ENV['APPLE_PRIVATE_KEY']),
      redirect_uri: ENV['APPLE_REDIRECT_URI']
      )
  end

  def sign_in_and_return
    sign_in(@user, store: true, bypass: false) # Devise method

    render status: 200, json: {
      status: "success",
      data: @user
    }
  end

  def unauthorized
    render status: 401, json: {
      status: "error"
    }
  end

  def unprocessable_entity
    render status: 422, json: {
      status: "error"
    }
  end
end