# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Api::BroadcastsController, type: :controller do
  let(:current_user) { create(:user, :admin) }

  describe '#index' do
    before do
      allow(MuxLiveStream).to receive(:new).and_return(double(id: 'id', key: 'key', playback_id: 'playback_id'))
    end

    it 'returns a list of all broadcasts ready for streaming in the project' do
      project = create(:project, name: 'first', account_id: current_user.primary_account.id)
      br1 = create(:broadcast, project: project, name: 'Created Bc', status: 'created')
      br2 = create(:broadcast, project: project, name: 'Idle Bc', status: 'idle')

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

      expect(response).to be_successful

      expect(response.body).to have_content('Created Bc')
      expect(response.body).to have_content('Idle Bc')
      expect(response.body).to have_content('created')
      expect(response.body).to have_content('idle')
      expect(response.body).to have_content('created_at')
    end

    it 'returns empty list if there are no broadcasts' do
      project = create(:project, name: 'empty', account_id: current_user.primary_account.id)
      sign_in_to_api(current_user)
      get :index, params: { project_id: project.id }
      expect(response).to be_successful

      expect(response.body).to have_content('[]')
    end

    it 'does not return broadcasts that are not ready to stream' do
      project = create(:project, name: 'first', account_id: current_user.primary_account.id)
      br1 = create(:broadcast, project: project, name: 'Created Bc', status: 'created')
      br2 = create(:broadcast, project: project, name: 'Active Bc', status: 'active')

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

      expect(response).to be_successful

      expect(response.body).to have_content('Created Bc')
      expect(response.body).to have_content('created')
      expect(response.body).not_to have_content('Active Bc')
      expect(response.body).not_to have_content('active')
    end

    it 'does not return broadcasts from another project' do
      project = create(:project, name: 'empty', account_id: current_user.primary_account.id)
      project2 = create(:project, name: 'with broadcasts', account_id: current_user.primary_account.id)
      create(:broadcast, project: project2, name: 'Created Bc', status: 'created')

      sign_in_to_api(current_user)
      get :index, params: { project_id: project.id }
      expect(response).to be_successful

      expect(response.body).to have_content('[]')
    end

    it 'does not return broadcasts from another account' do
      second_account = create(:account, name: 'second')
      project = create(:project, name: 'empty', account_id: current_user.primary_account.id)
      project2 = create(:project, name: 'with broadcasts', account_id: second_account.id)
      create(:broadcast, project: project2, name: 'Created Bc', status: 'created')

      sign_in_to_api(current_user)
      get :index, params: { project_id: project.id }
      expect(response).to be_successful

      expect(response.body).to have_content('[]')
    end
  end

  describe '#show' do
    it 'returns a single broadcast' do
      project = create(:project, name: 'first', account_id: current_user.primary_account.id)
      br1 = create(:broadcast, :with_stream, skip_create_callback: true, project: project, name: 'Created Bc', status: 'created')

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

      expect(response).to be_successful

      expect(response.body).to have_content('Created Bc')
      expect(response.body).to have_content('created')
      expect(response.body).to have_content('created_at')
    end

    it 'includes files relationship' do
      project = create(:project, name: 'first', account_id: current_user.primary_account.id)
      broadcast = create(:broadcast, :with_stream, :with_files, skip_create_callback: true, project: project)

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

      expect(response).to be_successful

      relationships = JSON.parse(response.body).dig('data', 'relationships')
      included = JSON.parse(response.body).dig('included')

      expect(relationships.keys).to include('files')
      expect(included.size).to eq 1
      expect(included.first.dig("id")).to eq broadcast.files.first.id.to_s
      expect(included.first.dig("type")).to eq 'active_storage_attachment'
    end
  end

  describe "#update" do
    it "uploads files to broadcast" do
      project = create(:project, name: 'first', account_id: current_user.primary_account.id)
      broadcast = create(:broadcast, :with_stream, skip_create_callback: true, project: project, name: 'Created Bc', status: 'created')
      
      sign_in_to_api(current_user)
      patch :update, params: file_params(project, broadcast)

      relationships = JSON.parse(response.body).dig('data', 'relationships')
      included = JSON.parse(response.body).dig('included')

      expect(relationships.keys).to include('files')
      expect(included.size).to eq 1
      expect(included.first.dig("id")).to eq broadcast.files.first.id.to_s
      expect(included.first.dig("type")).to eq 'active_storage_attachment'
    end

    context "when files param contains a signed_id string" do
      it "adds that file to the broadcast" do
        project = create(:project, name: 'first', account_id: current_user.primary_account.id)
        broadcast = create(:broadcast, :with_stream, skip_create_callback: true, project: project, status: 'created')
        blob = ActiveStorage::Blob.create_after_upload!(io: StringIO.new("Hello"), filename: "hello.txt", content_type: "text/plain")

        sign_in_to_api(current_user)
        patch :update, params: { project_id: project, id: broadcast, broadcast: { files: [blob.signed_id] } }

        relationships = JSON.parse(response.body).dig('data', 'relationships')
        included = JSON.parse(response.body).dig('included')

        expect(relationships.keys).to include('files')
        expect(included.size).to eq 1
        expect(included.first.dig("id")).to eq broadcast.files.first.id.to_s
        expect(included.first.dig("type")).to eq 'active_storage_attachment'
        expect(included.first.dig("attributes", "filename")).to eq 'hello.txt'
      end
    end
  end

  after do
    # Set the callback again or it will affect other test cases where the callback is required
    Broadcast.set_callback(:create, :after, :create_mux_live_stream)
  end

  private

  def file_params(project, broadcast)
    {
      :project_id => project.id,
      :id => broadcast.id,
      :broadcast => {
        files: [{
          io: file_base64,
          filename: "person_photo.png"
        }]
      }
    }
  end

  def file_base64
    Base64Image.from_image(file_fixture('person_photo.png')).data_uri
  end
end
