require 'rails_helper'

RSpec.describe User, type: :model do
  subject(:user) { User.new }

  describe "Associations" do
    it { should have_many(:schemes) }

    it "has many orders" do
      expect(User.reflect_on_association(:orders).macro).to eq(:has_many)
    end

    it "has many subscriptions" do
      expect(User.reflect_on_association(:subscriptions).macro).to eq(:has_many)
    end
  end

  describe "#name" do
    it "is invalid if name is blank" do
      expect(user.valid?).to be false
      expect(user.errors[:name]).to include "can't be blank"
    end

    it "is valid if name contains emoji" do
      user = User.create(email: "a@a.com", password: "password", name: "😀")
      expect(user.valid?).to be_truthy
    end
  end

  describe "#default_values" do
    it "sets default values after initialize" do
      user = User.new email: "alex@a.com"
      expect(user.name).to eq "alex"
    end
  end

  describe "#points_of_story" do
    it "returns the point user voted for a story" do
      user = User.create(email: 'a@a.com', password: 'password')
      story = Story.create(link: 'http://jira.com/123')
      user_story_point = UserStoryPoint.create user_id: user.id, story_id: story.id, points: 13
      expect(user.points_of_story(story.id)).to eq "13"
    end
  end

  describe "#display_name" do
    it "prefers email user name" do
      user.name = 'nickname'
      expect(user.display_name).to eq "nickname"
    end

    it "shows email address if user name does not exist" do
      user.email = 'a@a.com'
      expect(user.display_name).to eq "a@a.com"
    end
  end

  describe "#stories_groomed_count" do
    it "simply returns stories user voted" do
      user = User.create(email: 'a@a.com', password: 'password')
      UserStoryPoint.create(user_id: user.id, story_id: 1, points: 1)
      UserStoryPoint.create(user_id: user.id, story_id: 2, points: 13)
      expect(user.stories_groomed_count).to eq 2
    end
  end

  it { should have_attached_file(:avatar) }
  it { should validate_attachment_content_type(:avatar).
                allowing('image/png', 'image/gif').
                rejecting('text/plain', 'text/xml') }
  it { should validate_attachment_size(:avatar).
                less_than(2.megabytes) }

  describe "#letter_avatar" do
    it "returns medium size avatar if user uploaded avatar" do
      user.id = 1
      user.avatar = File.new "#{Rails.root}/spec/fixtures/avatar.png"

      expect(user.letter_avatar).to start_with "/system/users/avatars/000/000/001/medium/avatar.png"
    end
    
    it "returns user avatar if avatar set from oauth platform" do
      user.image = "image-from-twitter"

      expect(user.letter_avatar).to eq user.image
    end

    context "when user havent upload avatar" do
      it "returns avatar generated by first letter of name" do
        allow(user).to receive(:avatar?) { false }
        allow(user).to receive(:name) { "Alex" }
        expect(user.letter_avatar).to match /letter_avatars\/2\/A.+100.png/
      end

      it "returns avatar generated by first pinyin letter of name if its Chinese" do
        allow(user).to receive(:avatar?) { false }
        allow(user).to receive(:name) { "石" }
        expect(user.letter_avatar).to match /letter_avatars\/\d+\/S.+100.png/
      end

      it "returns avatar generated by first pinyin letter of name if its Chinese + digits + letters" do
        allow(user).to receive(:avatar?) { false }
        allow(user).to receive(:name) { "石alex" }
        expect(user.letter_avatar).to match /letter_avatars\/\d+\/S.+100.png/
      end
    end
  end

  describe "#email_verified?" do
    it "returns true if valid email" do
      user.email = "a@a.com"

      expect(user.email_verified?).to be_truthy
    end

    it "returns false if invalid email" do
      user.email = "a@@a.com"

      expect(user.email_verified?).to be_falsy
    end

  end

  describe ".find_for_oauth" do
    it "creates authorization and user if none exists" do
      auth_info = double(email: "alex@pokrex.com", image: "alex.png")
      auth_extra_rawinfo = double(name: "hlcfan")
      auth_extra = double(raw_info: auth_extra_rawinfo)
      auth = double(uid: "12345", provider: "weibo", info: auth_info, extra: auth_extra)

      user = User.find_for_oauth auth, nil

      expect(user.name).to eq "hlcfan"
      expect(user.email).to eq "alex@pokrex.com"
      expect(user.image).to eq "alex.png"
      expect(Authorization.find_by(user_id: user.id).uid).to eq "12345"
    end

    it "updates user image and create new authorization if login with oauth shared same email" do
      auth_info = double(email: "alex@pokrex.com", image: "alex.png")
      auth_extra_rawinfo = double(name: "hlcfan")
      auth_extra = double(raw_info: auth_extra_rawinfo)
      auth = double(uid: "12345", provider: "weibo", info: auth_info, extra: auth_extra)

      user = User.new name: "alex", email: "alex@pokrex.com", password: "what-ever"
      user.avatar = File.new "#{Rails.root}/spec/fixtures/avatar.png"
      user.save!

      user_updated = User.find_for_oauth auth, nil

      expect(user_updated.name).to eq "alex"
      expect(user_updated.email).to eq "alex@pokrex.com"
      expect(user_updated.image).to eq "alex.png"
      expect(Authorization.find_by(user_id: user.id).uid).to eq "12345"
    end
  end

  require 'active_support/testing/time_helpers'
  include ActiveSupport::Testing::TimeHelpers
  describe "#expand_premium_expiration" do
    it "expands user premium expiration date" do
      user = User.create(email: 'a@a.com', password: 'password')
      time = Time.parse("2018-11-13 14:12 UTC")
      travel_to time
      allow(Time.now).to receive(:utc) { time }
      expect(user.expand_premium_expiration(1.day)).to eq(true)
      expect(user.reload.premium_expiration).to eq(time + 1.day)
    end
  end

  describe "#premium?" do
    it "returns true if premium member" do
      user = User.create(email: 'a@a.com', password: 'password', premium_expiration: Time.now + 10.days)
      expect(user.premium?).to be true
    end

    it "returns false if non premium member" do
      user = User.create(email: 'a@a.com', password: 'password')
      expect(user.premium?).to be false
    end
  end

  describe "#subscription_active?" do
    it "returns true if user's latest subscription is active" do
      user = User.create(email: 'a@a.com', password: 'password')
      Subscription.create(user_id: user.id, status: 1)
      expect(user.subscription_active?).to be true
    end

    it "returns false if user's latest subscription is delete" do
      user = User.create(email: 'a@a.com', password: 'password')
      Subscription.create(user_id: user.id, status: 0)
      expect(user.subscription_active?).to be false
    end
  end

  describe "#subscription_cancel_url" do
    it "returns cancel url if has active subscription" do
      user = User.create(email: 'a@a.com', password: 'password')
      Subscription.create(user_id: user.id, status: 1, cancel_url: "http://cancel-url")
      expect(user.subscription_cancel_url).to eq("http://cancel-url")
    end

    it "returns nil if no active subscription" do
      user = User.create(email: 'a@a.com', password: 'password')
      expect(user.subscription_cancel_url).to be_nil
    end

  end
end
