# frozen_string_literal: true

require 'rails_helper'

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

  before do
    allow(BrayniacAI::Validation).to receive(:create).and_return(double(:validation, valid: true))
  end

  describe '#index' do
    it 'returns a succesful response' do
      create(:appearance_release, person_first_name: 'ct1', person_last_name: 'ct12', 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(:appearance_release, person_first_name: 'ct1', person_last_name: 'ct12', 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
      project = create(:project, account_id: current_user.primary_account.id)
      appearance_release = create(:appearance_release,
                                  :with_person_photo, :with_guardian_photo, :with_guardian_2_photo,
                                  project: project)

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

      [appearance_release.person_photo, appearance_release.guardian_photo, appearance_release.guardian_2_photo].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: 'ct1', project_id: project.id)
      small_photo = photo_base64
      guardian_photo = guardian_photo_base64
      signature = signature_base64
      @parameters = {
        contract_template_id: template.id,
        appearance_release: {
          signature: signature,
          person_phone: '123',
          person_first_name: 'aaa',
          person_last_name: 'bbb',
          minor: true,
          guardian_first_name: 'John',
          guardian_last_name: 'Doe',
          guardian_phone: '9191919191',
          signed_at: '2020-01-01 16:50:26 UTC',
          person_photo: {
            io: small_photo,
            filename: 'filenameee.jpg'
          }
        }
      }

      @guardian_info = {
        minor: true,
        guardian_name: 'Guardian',
        guardian_phone: '101010'
      }

      @guardian_photo = {
        guardian_photo: {
          io: guardian_photo,
          filename: 'guardianPhoto.jpeg'
        }
      }
      sign_in_to_api(current_user)
    end

    it 'returns 201 - created response' do
      post :create, params: @parameters
      expect(response.status).to eq 201

      expect(AppearanceRelease.last.signature).to be_attached
    end

    it 'saves signed on date correctly' do
      post :create, params: @parameters
      expect(response.status).to eq 201
      expect(AppearanceRelease.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(AppearanceRelease.last)
    end

    it 'runs add headshot collection uid background job' do
      expect do
        post :create, params: @parameters
      end.to have_enqueued_job(AddHeadshotCollectionUidToProjectJob).with(project)
    end

    it 'runs set tags for background releasable job' do
      expect do
        post :create, params: @parameters
      end.to have_enqueued_job(SetTagsForReleasableJob).with(AppearanceRelease.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,
        appearance_release: {
          person_name: 'aaa'
        }
      }

      parameters[:appearance_release][:person_photo] = {
        io: small_photo,
        filename: 'filenameee.jpg'
      }

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

    it 'returns 201 for minor without guardian photo' do
      params_without_guardian_photo = @parameters
      params_without_guardian_photo[:appearance_release].merge!(@guardian_info)

      post :create, params: params_without_guardian_photo
      expect(response.status).to eq 201
      expect(AppearanceRelease.last.signature).to be_attached
      expect(AppearanceRelease.last.guardian_photo).not_to be_attached
    end

    it 'returns 201 for minor with guardian photo' do
      params_with_guardian_photo = @parameters
      params_with_guardian_photo[:appearance_release].merge!(@guardian_info, @guardian_photo)

      post :create, params: params_with_guardian_photo
      expect(response.status).to eq 201

      appearance_release = AppearanceRelease.last
      photo = appearance_release.guardian_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)
      expect(appearance_release.signature).to be_attached
      expect(appearance_release.guardian_photo).to be_attached
    end

    it 'returns 201 for minor without second guardian photo' do
      post :create, params: @parameters.deep_merge(appearance_release: {
        minor: true,
        guardian_2_name: 'Guardian 2 Name',
        guardian_2_phone: '101010',
      })

      expect(response.status).to eq 201
      expect(AppearanceRelease.last.signature).to be_attached
      expect(AppearanceRelease.last.guardian_2_photo).not_to be_attached
    end

    it 'returns 201 for minor with second guardian photo' do
      post :create, params: @parameters.deep_merge(appearance_release: {
        minor: true,
        guardian_2_name: 'Guardian 2 Name',
        guardian_2_phone: '101010',
        guardian_2_photo: {
          io: guardian_photo_base64,
          filename: 'guardian_2_photo.jpeg'
        }
      })
      expect(response.status).to eq 201

      appearance_release = AppearanceRelease.last
      photo = appearance_release.guardian_2_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)
      expect(appearance_release.signature).to be_attached
      expect(appearance_release.guardian_2_photo).to be_attached
    end
  end

  private

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

  def guardian_photo_base64
    @guardian_photo_base64 ||= Base64Image.from_image(file_fixture('pratt.jpg')).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
