class GigyaSocialLoginService
  class GigyaNotificationError < Exception;
  end

  attr_reader :avatar_thumbnail_url, :birthday, :city, :email, :first_name, :gender,
    :gigya_connection, :gigya_id, :ip, :nickname, :provider, :response_message, :state,
    :user_agent, :zip

  attr_accessor :user

  def initialize(params)
    @avatar_thumbnail_url = params[:photoURL]
    @birthday = parse_birthday(params[:birthYear], params[:birthMonth], params[:birthDay])
    @city = blank_to_nil(params[:city])
    @email = params[:email]
    @first_name = params[:firstName]
    @gender = blank_to_nil(params[:gender])
    @gigya_connection = params.fetch(:gigya_connection)
    @gigya_id = params[:UID]
    @ip = params[:ip]
    @nickname = blank_to_nil(params[:nickname])
    @provider = params[:provider]
    @state = blank_to_nil(params[:state])
    @user_agent = params[:user_agent]
    @zip = blank_to_nil(params[:zip])
    @response_message = 'Sorry, that email has already been registered. Please use a different email.'
  end

  def sign_in_user
    if gigya_id_is_valid_primary_key
      user = plink_user_service.find_by_id(gigya_id.to_i)
    else
      user = find_or_create_user_by_email(email)
    end

    if user
      update_user_thumbnail(user)
      self.user = user
      GigyaLoginResponse.new(true, user.new_user?)
    else
      gigya_connection.delete_user(gigya_id)
      GigyaLoginResponse.new(false, false, response_message)
    end
  end

  class GigyaLoginResponse
    attr_reader :success, :message, :new_user

    def initialize(success, new_user, message = '')
      @success = success
      @new_user = new_user
      @message = message
    end

    def success?
      success
    end

    def new_user?
      new_user
    end
  end

private

  def parse_birthday(year, month, day)
    begin
      Time.zone.local(year.to_i, month.to_i, day.to_i)
    rescue ArgumentError
      nil
    end
  end

  def find_or_create_user_by_email(email)
    user = plink_user_service.find_by_email(email)

    if user && provider == 'twitter'
      nil
    else
      if user
        notify_gigya_registration(user)
      else
        create_user_from_gigya
      end
    end
  end

  def notify_gigya_registration(user)
    gigya_connection.notify_registration(gigya_id: gigya_id, site_user_id: user.id)
    user
  end

  def create_user_from_gigya
    user_creation_service = Plink::UserCreationService.new(user_params)
    if user_creation_service.valid?
      user = user_creation_service.create_user
      response = gigya_connection.notify_registration(gigya_id: gigya_id, site_user_id: user.id)

      raise GigyaNotificationError unless response.successful?
      user
    else
      @response_message = "Sorry, your user registration failed. Please register through our form instead of #{provider}."
      nil
    end
  end

  def update_user_thumbnail(user)
    user.update_attributes(avatar_thumbnail_url: @avatar_thumbnail_url) unless user.avatar_thumbnail_url?
  end

  def gigya_id_is_valid_primary_key
    gigya_id.to_i.to_s == gigya_id
  end

  def plink_user_service
    Plink::UserService.new
  end

  def user_params
    password = Plink::Password.autogenerated

    {
      avatar_thumbnail_url: avatar_thumbnail_url,
      birthday: birthday,
      city: city,
      email: email,
      first_name: first_name,
      ip: ip,
      is_male: is_male,
      password_hash: password.hashed_value,
      provider: provider,
      salt: password.salt,
      state: state,
      username: nickname,
      user_agent: user_agent,
      zip: zip
    }
  end

  def is_male
    if gender == 'm'
      true
    elsif gender == 'f'
      false
    else
      nil
    end
  end

  def blank_to_nil(param)
    param.blank? ? nil : param
  end
end
