#   Copyright (c) 2010-2011, Diaspora Inc.  This file is
#   licensed under the Affero General Public License version 3 or later.  See
#   the COPYRIGHT file.

require 'spec_helper'

describe Webfinger do
  let(:host_meta_xrd) { File.open(File.join(Rails.root, 'spec', 'fixtures', 'host-meta.fixture.html')).read }
  let(:webfinger_xrd) { File.open(File.join(Rails.root, 'spec', 'fixtures', 'webfinger.fixture.html')).read }
  let(:hcard_xml) { File.open(File.join(Rails.root, 'spec', 'fixtures', 'hcard.fixture.html')).read }
  let(:account){'foo@bar.com'}
  let(:account_in_fixtures){"alice@localhost:9887"}
  let(:finger){Webfinger.new(account)}
  let(:host_meta_url){"http://#{AppConfig[:pod_uri].authority}/webfinger?q="}

  describe '#intialize' do
    it 'sets account ' do
      n = Webfinger.new("mbs348@gmail.com")
      n.account.should_not be nil
    end

    it "downcases account and strips whitespace, and gsub 'acct:'" do
      n = Webfinger.new("acct:BIGBOY@Example.Org ")
      n.account.should == 'bigboy@example.org'
    end

    it 'should set ssl as the default' do
      foo = Webfinger.new(account)
      foo.ssl.should be true
    end
  end

  describe '.in_background' do
    it 'enqueues a Jobs::FetchWebfinger job' do
      Resque.should_receive(:enqueue).with(Jobs::FetchWebfinger, account)
      Webfinger.in_background(account)
    end
  end
  
  describe '#fetch' do
    it 'works' do
      finger = Webfinger.new(account_in_fixtures)
      finger.stub(:host_meta_xrd).and_return(host_meta_xrd)
      finger.stub(:hcard_xrd).and_return(hcard_xml)
      finger.stub(:webfinger_profile_xrd).and_return(webfinger_xrd)
      person = finger.fetch
      person.should be_valid
      person.should be_a Person
    end

  end

  describe '#get' do
    it 'makes a request and grabs the body' do
      url ="https://bar.com/.well-known/host-meta"
      stub_request(:get, url).
        to_return(:status => 200, :body => host_meta_xrd)

      finger.get(url).should == host_meta_xrd
    end

    it 'follows redirects' do
      redirect_url = "http://whereami.whatisthis/host-meta"

      stub_request(:get, "https://bar.com/.well-known/host-meta").
        to_return(:status => 302, :headers => { 'Location' => redirect_url })

      stub_request(:get, redirect_url).
        to_return(:status => 200, :body => host_meta_xrd)

      finger.host_meta_xrd

      a_request(:get, redirect_url).should have_been_made
    end
    
    it 'returns false on 404' do
      url ="https://bar.com/.well-known/host-meta"
      stub_request(:get, url).
        to_return(:status => 404, :body => nil)

      finger.get(url).should_not == nil
      finger.get(url).should == false
    end
  end

  describe 'existing_person_with_profile?' do
    it 'returns true if cached_person is present and has a profile' do
      finger.should_receive(:cached_person).twice.and_return(Factory(:person))
      finger.existing_person_with_profile?.should be_true
    end

    it 'returns false if it has no person' do
      finger.stub(:cached_person).and_return false
      finger.existing_person_with_profile?.should be_false
    end

    it 'returns false if the person has no profile' do
      p = Factory(:person)
      p.profile = nil
      finger.stub(:cached_person).and_return(p)
      finger.existing_person_with_profile?.should be_false
    end
  end

  describe 'cached_person' do
    it 'sets the person by looking up the account from Person.by_account_identifier' do
      person = stub
      Person.should_receive(:by_account_identifier).with(account).and_return(person)
      finger.cached_person.should == person
      finger.person.should == person
    end
  end


  describe 'create_or_update_person_from_webfinger_profile!' do
    context 'with a cached_person' do
      it 'calls Person#assign_new_profile_from_hcard with the fetched hcard' do
        finger.hcard_xrd = hcard_xml
        finger.stub(:person).and_return(bob.person)
        bob.person.should_receive(:assign_new_profile_from_hcard).with(finger.hcard)
        finger.create_or_update_person_from_webfinger_profile!
      end
    end

    context 'with no cached person' do
      it 'sets person based on make_person_from_webfinger' do
        finger.stub(:person).and_return(nil)
        finger.should_receive(:make_person_from_webfinger)
        finger.create_or_update_person_from_webfinger_profile!
      end
    end
  end

  describe '#host_meta_xrd' do
    it 'calls #get with host_meta_url' do
      finger.stub(:host_meta_url).and_return('meta')
      finger.should_receive(:get).with('meta')
      finger.host_meta_xrd
    end

    it 'should retry with ssl off a second time' do
      finger.should_receive(:get).and_raise(StandardError)
      finger.should_receive(:get)
      finger.host_meta_xrd
      finger.ssl.should be false
    end
  end

  describe '#hcard' do
    it 'calls HCard.build' do
      finger.stub(:hcard_xrd).and_return(hcard_xml)
      HCard.should_receive(:build).with(hcard_xml).and_return true
      finger.hcard.should_not be_nil
    end
  end

  describe '#webfinger_profile' do
    it 'constructs a new WebfingerProfile object' do
      finger.stub(:webfinger_profile_xrd).and_return(webfinger_xrd)
      WebfingerProfile.should_receive(:new).with(account, webfinger_xrd)
      finger.webfinger_profile
    end
  end

  describe '#webfinger_profile_url' do
    it 'returns the llrd link for a valid host meta' do
      finger.stub(:host_meta_xrd).and_return(host_meta_xrd)
      finger.webfinger_profile_url.should_not be_nil
    end

    it 'returns nil if no link is found' do
      finger.stub(:host_meta_xrd).and_return(nil)
      finger.webfinger_profile_url.should be_nil
    end
  end

  describe '#webfinger_profile_xrd' do
    it 'calls #get with the hcard_url' do
      finger.stub(:hcard_url).and_return("url")
      finger.should_receive(:get).with("url")
      finger.hcard_xrd
    end
  end

  describe '#make_person_from_webfinger' do
    it 'with an hcard and a webfinger_profile, it calls Person.create_from_webfinger' do
      finger.stub(:hcard).and_return("hcard")
      finger.stub(:webfinger_profile_xrd).and_return("webfinger_profile_xrd")
      finger.stub(:webfinger_profile).and_return("webfinger_profile")
      Person.should_receive(:create_from_webfinger).with("webfinger_profile", "hcard")
      finger.make_person_from_webfinger
    end
    
    it 'with an false xrd it does not call Person.create_from_webfinger' do
      finger.stub(:webfinger_profile_xrd).and_return(false)
      Person.should_not_receive(:create_from_webfinger)
      finger.make_person_from_webfinger
    end
  end



  describe '#host_meta_url' do
    it 'should return canonical host-meta url for http' do
      finger.ssl = false
      finger.host_meta_url.should == "http://bar.com/.well-known/host-meta"
    end

    it 'can return the https version' do
      finger.host_meta_url.should == "https://bar.com/.well-known/host-meta"
    end
  end

  describe 'swizzle' do
    it 'gsubs out {uri} for the account' do
      string = "{uri} is the coolest"
      finger.swizzle(string).should == "#{finger.account} is the coolest"
    end
  end
end
