require 'spec_helper'

describe Praxis::MediaType do
  let(:owner_resource) { instance_double(Person, id: 100, name: /[:name:]/.gen, href: '/') }
  let(:manager_resource) { instance_double(Person, id: 101, name: /[:name:]/.gen, href: '/') }
  let(:custodian_resource) { instance_double(Person, id: 102, name: /[:name:]/.gen, href: '/') }
  let(:residents_summary_resource) do
    instance_double(Person::CollectionSummary, href: "/people", size: 2)
  end

  let(:resource) do
    double('address',
      id: 1,
      name: 'Home',
      owner: owner_resource,
      manager: manager_resource,
      custodian: custodian_resource,
      residents_summary: residents_summary_resource,
      fields: {id: true, name: true}
    )
  end

  subject(:address) { Address.new(resource) }


  context 'attributes' do
    its(:id)    { should eq(1) }
    its(:name)  { should eq('Home') }
    its(:owner) { should be_instance_of(Person) }
  end


  context 'loading' do
    it do
      Person.load({id: 1})
      Person.load(owner_resource)

    end
  end


  context 'accessor methods' do
    subject(:address_klass) { address.class }

    context '#identifier' do
      context 'in praxis v1.0 and beyond' do
        it 'should be a kind of Praxis::MediaTypeIdentifier' do
          pending('interface-breaking change') if Praxis::VERSION =~ /^0/
          expect(subject.identifier).to be_kind_of(Praxis::MediaTypeIdentifier)
        end
      end
    end

    its(:description) { should be_kind_of(String) }

  end

  context "rendering" do
    subject(:output) { address.render(view: :default) }

    its([:id])    { should eq(address.id) }
    its([:name])  { should eq(address.name) }
    its([:owner]) { should eq(Person.dump(owner_resource, view: :default)) }
    its([:fields]) { should eq(address.fields.dump ) }

  end

  context 'describing' do

    subject(:described){ Address.describe }

    its(:keys) { should match_array( [:attributes, :description, :display_name, :family, :id, :identifier, :key, :name, :views, :requirements] ) }
    its([:attributes]) { should be_kind_of(::Hash) }
    its([:description]) { should be_kind_of(::String) }
    its([:display_name]) { should be_kind_of(::String) }
    its([:family]) { should be_kind_of(::String) }
    its([:id]) { should be_kind_of(::String) }
    its([:name]) { should be_kind_of(::String) }
    its([:identifier]) { should be_kind_of(::String) }
    its([:key]) { should be_kind_of(::Hash) }
    its([:views]) { should be_kind_of(::Hash) }

    its([:description]) { should eq(Address.description) }
    its([:display_name]) { should eq(Address.display_name) }
    its([:family]) { should eq(Address.family) }
    its([:id]) { should eq(Address.id) }
    its([:name]) { should eq(Address.name) }
    its([:identifier]) { should eq(Address.identifier.to_s) }
    it 'should include the defined views' do
      expect( subject[:views].keys ).to match_array([:default, :master])
    end
    it 'should include the defined attributes' do
      expect( subject[:attributes].keys ).to match_array([:id, :name, :owner, :custodian, :residents, :residents_summary, :fields])
    end
  end

  context 'using blueprint caching' do
    it 'has specs'
  end

  context Praxis::MediaType::FieldResolver do
    let(:expander) { Praxis::FieldExpander }
    let(:user_view) { User.views[:default] }

    let(:fields) { expander.expand(user_view) }

    let(:field_resolver) { Praxis::MediaType::FieldResolver }

    subject(:output) { field_resolver.resolve(User,fields) }

    context 'resolving collections' do
      let(:fields) { {:id=>true, :posts=>[{:href=>true}]}}
      it 'strips arrays from the incoming fields' do
        expect(output).to eq(id: true, posts: {href: true})
      end

      it 'supports multi-dimensional collections' do
        fields = {
          id: true,
          post_matrix:[[{title: true, href: true}]]
        }
        output = field_resolver.resolve(User,fields)
        expect(output).to eq(id: true, post_matrix:{href: true, title: true})
      end

      it 'supports nesting structs and arrays collections' do
        fields = {
         id: true,
         daily_posts: [
           {day: true, posts: [{id: true}]}
         ]
        }
        output = field_resolver.resolve(User,fields)
        expect(output).to eq(id: true, daily_posts:{day: true, posts: {id:true}})
      end
    end

  end


end