# frozen_string_literal: true

require 'rails_helper'

releases = [
  {
    type: :location_release,
    obligatory_attribute: :name
  },
  {
    type: :material_release,
    obligatory_attribute: :name
  }
]

releases.each do |release|
  controller = "Api::#{release[:type].to_s.pluralize.camelize}Controller".constantize

  RSpec.describe controller, type: :controller do
    let(:current_user) { create(:user) }
    let(:project) { create(:project, name: 'first', account: current_user.primary_account) }

    describe '#index' do
      it 'returns a succesful response' do
        r = create(release[:type], release[:obligatory_attribute] => 'contract template 1', :project_id => project.id)

        sign_in_to_api(current_user)
        get :index, params: { project_id: project.id }

        expect(response).to be_successful
        old_body = response.body

        get :index, params: { project_id: project.id, updated_since: (DateTime.current + 10.days).to_date.to_s }
        expect(response.body).not_to eq(old_body)
      end
    end

    describe '#show' do
      it 'returns a succesful response' do
        tested_release = create(release[:type], release[:obligatory_attribute] => 'contract template 1', :project_id => project.id)

        sign_in_to_api(current_user)
        get :show, params: { id: tested_release.id }

        expect(response).to be_successful
      end

      it 'includes photos' do
        tested_release = create("#{release[:type]}_with_photo", release[:obligatory_attribute] => 'Release Name', project: project)

        sign_in_to_api(current_user)
        get :show, params: { id: tested_release.id }

        tested_release.photos.each do |photo|
          data = {
            'id' => photo.id.to_s,
            'type' => 'active_storage_attachment',
            'attributes' => {
              'content_type' => photo.content_type,
              'filename' => photo.filename.to_s,
              'url' => photo_path_for(photo),
              'thumbnail_url' => photo_variant_path_for(photo, '150x150')
            }
          }

          expect(response_body_included_attributes).to include(data)
        end
      end
    end

    describe '#create' do
      before do
        template = create(:contract_template, name: 'contract template 1', project_id: project.id)
        small_photo = photo_base64
        signature = signature_base64
        @parameters = {
          contract_template_id: template.id,
          release[:type] => {
            release[:obligatory_attribute] => 'aaa',
            :signature => signature,
            :person_phone => '123',
            :person_first_name => 'aaa',
            :person_last_name => 'aaa',
            :signed_at => '2020-01-01 16:50:26 UTC',
            :photos => [{
              io: small_photo,
              filename: 'photo1.jpg'
            }]

          }
        }

        sign_in_to_api(current_user)
      end

      it 'returns 201 - created response' do
        post :create, params: @parameters
        releasable = release[:type].to_s.classify.constantize.last

        expect(response.status).to eq 201

        expect(releasable.signature).to be_attached
      end

      it 'saves signed on date correctly' do
        post :create, params: @parameters
        expect(response.status).to eq 201

        expect(release[:type].to_s.classify.constantize.last.signed_on).to eq '01/01/20'
      end

      it 'runs attach contract to background job' do
        expect do
          post :create, params: @parameters
        end.to have_enqueued_job(AttachContractToReleasableJob).with(release[:type].to_s.classify.constantize.last)
      end

      it 'runs set tags for releasable background job' do
        expect do
          post :create, params: @parameters
        end.to have_enqueued_job(SetTagsForReleasableJob).with(release[:type].to_s.classify.constantize.last)
      end

      it 'fails if there is no signature' do
        template = create(:contract_template, name: 'ct1', project_id: project.id)
        small_photo = photo_base64
        parameters = {
          contract_template_id: template.id,
          release[:type] => {
            release[:obligatory_attribute] => 'aaa bbb'
          }
        }

        if release[:type] == :appearance_release
          parameters[release[:type]][:person_photo] = {
            io: small_photo,
            filename: 'filenameee.jpg'
          }
        else
          parameters[release[:type]][:photos] = [{
            io: small_photo,
            filename: 'photo1.jpg'
          }]
        end

        sign_in_to_api(current_user)
        expect do
          post :create, params: parameters
        end.to raise_error(ActiveRecord::RecordInvalid)
      end
    end

    describe '#update' do
      it 'returns 200 - successful response' do
        tested_release = create(release[:type], release[:obligatory_attribute] => 'contract template 1',
                                                :project_id => project.id,
                                                :person_phone => '123',
                                                :person_name => 'aaa bbb')

        small_photo = photo_base64

        parameters = {
          :id => tested_release.id,
          release[:type] => {
            photos: [{
              io: small_photo,
              filename: 'photo1.jpg'
            }]
          }
        }

        sign_in_to_api(current_user)
        put :update, params: parameters
        expect(response.status).to eq 200
      end
    end
  end

  private

  def photo_base64
    @photo_base64 ||= Base64Image.from_image(file_fixture('person_photo.png')).data_uri
  end

  def signature_base64
    @signature_base64 ||= Base64Image.from_image(file_fixture('signature.png')).data_uri
  end

  def photo_path_for(attachment)
    Rails.application.routes.url_helpers.rails_blob_url(attachment, host: AppHost.new.domain_with_port)
  end

  def photo_variant_path_for(attachment, _size)
    Rails.application.routes.url_helpers.rails_representation_url(attachment.variant(resize: '150x150'), host: AppHost.new.domain_with_port)
  end

  def response_body_data_attributes
    JSON.parse(response.body).dig('data', 'attributes')
  end

  def response_body_included_attributes
    JSON.parse(response.body).dig('included')
  end
end
