# frozen_string_literal: true

describe 'Templates API' do
  let(:account) { create(:account, :with_testing_account) }
  let(:testing_account) { account.testing_accounts.first }
  let(:author) { create(:user, account:) }
  let(:testing_author) { create(:user, account: testing_account) }
  let(:folder) { create(:template_folder, account:) }
  let(:template_preferences) { { 'request_email_subject' => 'Subject text', 'request_email_body' => 'Body Text' } }

  before do
    allow(Accounts).to receive(:link_expires_at).and_return(Accounts::LINK_EXPIRES_AT)
  end

  describe 'GET /api/templates' do
    it 'returns a list of templates' do
      templates = [
        create(:template, account:,
                          author:,
                          folder:,
                          external_id: SecureRandom.base58(10),
                          preferences: template_preferences),
        create(:template, account:,
                          author:,
                          folder:,
                          external_id: SecureRandom.base58(10),
                          preferences: template_preferences)
      ].reverse

      get '/api/templates', headers: { 'x-auth-token': author.access_token.token }

      expect(response).to have_http_status(:ok)
      expect(response.parsed_body['pagination']).to eq(JSON.parse({
        count: templates.size,
        next: templates.last.id,
        prev: templates.first.id
      }.to_json))
      expect(response.parsed_body['data']).to eq(JSON.parse(templates.map { |t| template_body(t) }.to_json))
    end
  end

  describe 'GET /api/templates/:id' do
    it 'returns a template' do
      template = create(:template, account:,
                                   author:,
                                   folder:,
                                   external_id: SecureRandom.base58(10),
                                   preferences: template_preferences)

      get "/api/templates/#{template.id}", headers: { 'x-auth-token': author.access_token.token }

      expect(response).to have_http_status(:ok)
      expect(response.parsed_body).to eq(JSON.parse(template_body(template).to_json))
    end

    it 'returns an authorization error if test account API token is used with a production template' do
      template = create(:template, account:,
                                   author:,
                                   folder:,
                                   external_id: SecureRandom.base58(10),
                                   preferences: template_preferences)

      get "/api/templates/#{template.id}", headers: { 'x-auth-token': testing_author.access_token.token }

      expect(response).to have_http_status(:forbidden)
      expect(response.parsed_body).to eq(
        JSON.parse({ error: "Template #{template.id} not found using testing API key; " \
                            'Use production API key to access production templates.' }.to_json)
      )
    end

    it 'returns an authorization error if production account API token is used with a test template' do
      template = create(:template, account: testing_account,
                                   author: testing_author,
                                   folder:,
                                   external_id: SecureRandom.base58(10),
                                   preferences: template_preferences)

      get "/api/templates/#{template.id}", headers: { 'x-auth-token': author.access_token.token }

      expect(response).to have_http_status(:forbidden)
      expect(response.parsed_body).to eq(
        JSON.parse({ error: "Template #{template.id} not found using production API key; " \
                            'Use testing API key to access testing templates.' }.to_json)
      )
    end
  end

  describe 'PUT /api/templates' do
    let(:template) do
      create(:template, account:,
                        author:,
                        folder:,
                        external_id: SecureRandom.base58(10),
                        preferences: template_preferences)
    end

    it 'updates a template' do
      put "/api/templates/#{template.id}", headers: { 'x-auth-token': author.access_token.token }, params: {
        name: 'Updated Template Name',
        external_id: '123456'
      }.to_json

      expect(response).to have_http_status(:ok)

      template.reload

      expect(template.name).to eq('Updated Template Name')
      expect(template.external_id).to eq('123456')
      expect(response.parsed_body).to eq(JSON.parse({
        id: template.id,
        updated_at: template.updated_at
      }.to_json))
    end

    it "enables the template's shared link" do
      expect do
        put "/api/templates/#{template.id}", headers: { 'x-auth-token': author.access_token.token }, params: {
          shared_link: true
        }.to_json
      end.to change { template.reload.shared_link }.from(false).to(true)
    end

    it "disables the template's shared link" do
      template.update(shared_link: true)

      expect do
        put "/api/templates/#{template.id}", headers: { 'x-auth-token': author.access_token.token }, params: {
          shared_link: false
        }.to_json
      end.to change { template.reload.shared_link }.from(true).to(false)
    end
  end

  describe 'DELETE /api/templates/:id' do
    it 'archives a template' do
      template = create(:template, account:,
                                   author:,
                                   folder:,
                                   external_id: SecureRandom.base58(10),
                                   preferences: template_preferences)

      delete "/api/templates/#{template.id}", headers: { 'x-auth-token': author.access_token.token }

      expect(response).to have_http_status(:ok)

      template.reload

      expect(template.archived_at).not_to be_nil
      expect(response.parsed_body).to eq(JSON.parse({
        id: template.id,
        archived_at: template.archived_at
      }.to_json))
    end
  end

  describe 'POST /api/templates/:id/clone' do
    it 'clones a template' do
      template = create(:template, account:,
                                   author:,
                                   folder:,
                                   external_id: SecureRandom.base58(10),
                                   preferences: template_preferences)

      expect do
        post "/api/templates/#{template.id}/clone", headers: { 'x-auth-token': author.access_token.token }, params: {
          name: 'Cloned Template Name',
          external_id: '123456'
        }.to_json
      end.to change(Template, :count)

      expect(response).to have_http_status(:ok)

      cloned_template = Template.last

      expect(cloned_template.name).to eq('Cloned Template Name')
      expect(cloned_template.external_id).to eq('123456')
      expect(response.parsed_body).to eq(JSON.parse(clone_template_body(cloned_template).to_json))
    end
  end

  private

  def template_body(template)
    template_attachment_uuid = template.schema.first['attachment_uuid']
    attachment = template.schema_documents.preload(:blob).find { |e| e.uuid == template_attachment_uuid }
    first_page_blob =
      ActiveStorage::Attachment.joins(:blob)
                               .where(blob: { filename: '0.png' })
                               .where(record_id: template.schema_documents.map(&:id),
                                      record_type: 'ActiveStorage::Attachment',
                                      name: :preview_images)
                               .preload(:blob)
                               .first
                               .blob

    {
      id: template.id,
      slug: template.slug,
      name: template.name,
      fields: template.fields,
      submitters: [
        {
          name: 'First Party',
          uuid: template.submitters.first['uuid']
        }
      ],
      author: {
        id: author.id,
        first_name: author.first_name,
        last_name: author.last_name,
        email: author.email
      },
      documents: [
        {
          id: template.documents.first.id,
          uuid: template.documents.first.uuid,
          url: ActiveStorage::Blob.proxy_url(attachment.blob, expires_at: Accounts::LINK_EXPIRES_AT),
          preview_image_url: ActiveStorage::Blob.proxy_url(first_page_blob, expires_at: Accounts::LINK_EXPIRES_AT),
          filename: 'sample-document.pdf'
        }
      ],
      preferences: {
        'request_email_subject' => 'Subject text',
        'request_email_body' => 'Body Text'
      },
      schema: [
        {
          attachment_uuid: template_attachment_uuid,
          name: 'sample-document'
        }
      ],
      shared_link: template.shared_link,
      author_id: author.id,
      archived_at: nil,
      created_at: template.created_at,
      updated_at: template.updated_at,
      folder_id: folder.id,
      folder_name: folder.name,
      source: 'native',
      external_id: template.external_id,
      application_key: template.external_id
    }
  end

  def clone_template_body(cloned_template)
    body = template_body(cloned_template).merge(source: 'api')
    body[:fields].each_with_index do |field, index|
      field.merge!(
        'submitter_uuid' => cloned_template.fields[index]['submitter_uuid'],
        'uuid' => cloned_template.fields[index]['uuid']
      )
    end

    body
  end
end
