require "rails_helper"

RSpec.describe MatchesPresenter do
  let(:project) { build(:project) }
  let(:video_analysis) { instance_double(VideoAnalysis) }
  let(:audio_analysis) { instance_double(AudioAnalysis) }

  describe "#build_chronological_matches" do
    context "when video analysis success" do
      let(:video) { create(:video, project: project, analysis_status: :success) }

      it "returns suggested_matches sorted by most recent first" do
        appearance_release = create(:appearance_release, project: project)

        appearance = BrayniacAI::FacialRecognitionResult.new(external_image_id: "appearance_release_#{appearance_release.id}", start_time: 100)
        allow(video_analysis).to receive(:first_appearances).and_return([appearance])

        edl_event_response = build(:edl_event,
          channel: "V",
          start_time: 0,
          timecode_in: "00:00:00:00",
          timecode_out: "00:00:01:00",
          matches: [1, 2],
        )

        results = described_class.new(video, video_analysis, audio_analysis, [edl_event_response], []).build_chronological_matches

        expect(results.count).to eq 1
        expect(results.first.elapsed_time_until_appearance).to eq 0.12
        expect(results.first.photo.name).to eq "person_photo"
        expect(results.first.name).to eq "Jane Doe"
        expect(results.first.appears_at_timecode).to eq Timecode.new("00:00:00:03")
      end
    end

    context "when video analysis not success" do
      let(:video) { create(:video, project: project, analysis_status: :pending) }

      it "returns empty array" do
        expect(described_class.new(video, video_analysis, audio_analysis, [], []).build_chronological_matches).to eq []
      end
    end
  end

  describe "#build_graphics_matches" do
    context "when video analysis success" do
      let(:video) do
        create(:video,
          project: project,
          analysis_status: :success,
          graphics_elements: build_list(:graphics_element, 1, source_file_name: "my_file.mp4", timecode_in: "00:00:00:00")
        )
      end

      it "returns graphics elements matches sorted by most recent first" do
        earlier_edl_event_response = build(:edl_event,
          start_time: 0,
          timecode_in: "00:00:00:00",
          timecode_out: "00:00:01:00",
          source_file_name: "my_file.mp4",
        )
        later_edl_event_response = build(:edl_event,
          start_time: 100,
          timecode_in: "00:00:10:00",
          timecode_out: "00:00:11:00",
          source_file_name: "another_file.mp4",
        )

        results = described_class.new(
          video,
          video_analysis,
          audio_analysis,
          [],
          [earlier_edl_event_response, later_edl_event_response],
        ).build_graphics_matches

        expect(results.count).to eq 2
        expect(results.first.start_time).to eq 100
        expect(results.first.elapsed_time_until_appearance).to eq 0.12
        expect(results.first.filename).to eq "another_file.mp4"
        expect(results.first.appears_at_timecode).to eq Timecode.new("00:00:00:03")
        expect(results.first.confirmed).to be false
        expect(results.first.timecode_in).to eq "00:00:10:00"
        expect(results.second.start_time).to eq 0
        expect(results.second.elapsed_time_until_appearance).to eq 0.0
        expect(results.second.appears_at_timecode).to eq Timecode.new("00:00:00:00")
        expect(results.second.filename).to eq "my_file.mp4"
        expect(results.second.confirmed).to be true
        expect(results.second.timecode_in).to eq "00:00:00:00"
      end

      it "does not return graphics elements matches that have empty source_file_name" do
        null_source_file_edl_event_response = build(:edl_event,
          source_file_name: nil,
        )
        empty_source_file_edl_event_response = build(:edl_event,
          source_file_name: "",
        )

        results = described_class.new(
          video,
          video_analysis,
          [],
          [
            null_source_file_edl_event_response,
            empty_source_file_edl_event_response,
          ],
          [],
        ).build_graphics_matches

        expect(results).to eq []
      end
    end

    context "when video analysis not success" do
      let(:video) { create(:video, project: project, analysis_status: :pending) }

      it "returns empty array" do
        expect(described_class.new(video, video_analysis, [], [], []).build_graphics_matches).to eq []
      end
    end
  end

  describe "#build_chronological_audio_matches" do
    context "when audio analysis success" do
      let(:video) { create(:video, project: project, audio_analysis_status: :success) }

      it "returns audio_matches sorted by most recent first" do
        acquired_media_release = create(:acquired_media_release,
          project: project,
          file_infos: [
            build(:file_info, id: 3, filename: "acquired_media_1")
          ]
        )
        music_release = create(:music_release,
          project: project,
          file_infos: [
            build(:file_info, id: 1, filename: "original_music_1"),
            build(:file_info, id: 2, filename: "original_music_2"),
          ]
        )
        audio_confirmation = create(:audio_confirmation,
          video: video,
          source_file_name: "original_music_2",
          timecode_in: "00:00:00:00",
        )

        audio_analysis = OpenStruct.new(
          results: [
            OpenStruct.new(
              uid: "2",
              requested_filename: "original_music_2",
              type: "original_music",
              audio_data: OpenStruct.new(
                filename: "original_music_2",
                composers: [],
                publishers: [],
                catalog: "",
                title: "",
              ),
              edl: [
                OpenStruct.new( 
                  start_time: 0,
                  timecode_in: "00:00:00:00",
                ),
              ]
            ),
            OpenStruct.new(
              uid: "1",
              requested_filename: "original_music_1",
              type: "original_music",
              audio_data: OpenStruct.new(
                filename: "original_music_1",
                composers: [],
                publishers: [],
                catalog: "",
                title: "",
              ),
              edl: [
                OpenStruct.new( 
                  start_time: 5000,
                  timecode_in: "00:00:05:00",
                ),
              ]
            ),
            OpenStruct.new(
              uid: "3",
              requested_filename: "acquired_media_1",
              type: "acquired_media",
              audio_data: OpenStruct.new(
                filename: "acquired_media_1",
                composers: [],
                publishers: [],
                catalog: "",
                title: "",
              ),
              edl: [
                OpenStruct.new( 
                  start_time: 1000,
                  timecode_in: "00:00:01:00",
                ),
              ]
            ),
            OpenStruct.new(
              uid: nil,
              requested_filename: "library_music_1",
              type: "library_music",
              audio_data: OpenStruct.new(
                filename: "library_music_1",
                composers: [OpenStruct.new(name: "Beethoven", affiliation: "Affiliation", percentage: "100.0%")],
                publishers: [OpenStruct.new(name: "Jingle Punks", affiliation: "Affiliation", percentage: "100.0%")],
                catalog: "MIBE",
                title: "Library Music",
              ),
              edl: [
                OpenStruct.new( 
                  start_time: 2000,
                  timecode_in: "00:00:02:00",
                ),
              ]
            ),
          ]
        )

        results = described_class.new(
          video,
          video_analysis,
          audio_analysis,
          [],
          [],
        ).build_chronological_audio_matches

        expect(results.count).to eq 4
        expect(results.first).to have_attributes(
          elapsed_time_until_appearance: 5.0,
          filename: "original_music_1",
          appears_at_timecode: Timecode.new("00:00:05:00"),
          timecode_in: "00:00:05:00",
          confirmed: false,
          composer_info: "Beethoven, Affiliation, 100.0%",
          publisher_info: "Jingle Punks, Affiliation, 100.0%",
          catalog: "",
          title: "",
          confirmation_type: "original_music",
          edl_type: "all_tracks",
        )
        expect(results.second).to have_attributes(
          elapsed_time_until_appearance: 2.0,
          filename: "library_music_1",
          appears_at_timecode: Timecode.new("00:00:02:00"),
          timecode_in: "00:00:02:00",
          confirmed: false,
          composer_info: "Beethoven, Affiliation, 100.0%",
          publisher_info: "Jingle Punks, Affiliation, 100.0%",
          catalog: "MIBE",
          title: "Library Music",
          confirmation_type: "library_music",
          edl_type: "all_tracks",
        )
        expect(results.third).to have_attributes(
          elapsed_time_until_appearance: 1.0,
          filename: "acquired_media_1",
          appears_at_timecode: Timecode.new("00:00:01:00"),
          timecode_in: "00:00:01:00",
          confirmed: false,
          composer_info: "",
          publisher_info: "",
          catalog: "",
          title: "",
          confirmation_type: "acquired_media",
          edl_type: "all_tracks",
        )
        expect(results.fourth).to have_attributes(
          elapsed_time_until_appearance: 0.0,
          filename: "original_music_2",
          appears_at_timecode: Timecode.new("00:00:00:00"),
          timecode_in: "00:00:00:00",
          confirmed: true,
          composer_info: "Beethoven, Affiliation, 100.0%",
          publisher_info: "Jingle Punks, Affiliation, 100.0%",
          catalog: "",
          title: "",
          confirmation_type: "original_music",
          edl_type: "all_tracks",
        )
      end

      context "when audio_only_edl attached" do
        it "returns audio_matches with edl_type " do
          video = create(:video, :with_audio_only_edl_file, project: project, audio_analysis_status: :success)
          audio_analysis = OpenStruct.new(
            results: [
              OpenStruct.new(
                uid: "2",
                requested_filename: "source_file_name",
                type: "acquired_media",
                audio_data: OpenStruct.new(
                  filename: "source_file_name",
                  composers: [],
                  publishers: [],
                  catalog: "",
                  title: "",
                ),
                edl: [
                  OpenStruct.new( 
                    source_file_name: "source_file_name",
                    start_time: 0,
                    timecode_in: "00:00:00:00",
                  ),
                ]
              ),
            ]
          )

          results = described_class.new(
            video,
            video_analysis,
            audio_analysis,
            [],
            [],
          ).build_chronological_audio_matches

          expect(results.first).to have_attributes(
            edl_type: "audio",
          )
        end
      end
    end

    context "when video analysis not success" do
      let(:video) { create(:video, project: project, audio_analysis_status: :pending) }

      it "returns empty array" do
        expect(described_class.new(video, video_analysis, audio_analysis, [], []).build_chronological_audio_matches).to eq []
      end
    end
  end

  describe "#all_tracks_edl_events" do
    let(:video) { create(:video, project: project, analysis_status: :pending) }

    it "returns edl events sorted by start time ascending" do
      earlier_edl_event_response = build(:edl_event,
        channel: "V",
        start_time: 0,
        timecode_in: "00:00:00:00",
        timecode_out: "00:00:01:00",
        duration: 1,
        source_file_name: "my_file.mp4",
        clip_name: "my_clip.mp4",
        description: "This is a great clip",
        matches: [],
      )
      later_edl_event_response = build(:edl_event,
        channel: "A1",
        start_time: 100,
        timecode_in: "00:00:10:00",
        timecode_out: "00:00:11:00",
        duration: 1,
        source_file_name: "another_file.mp4",
        clip_name: "another_clip.mp4",
        description: "This is a great clip",
        matches: [],
      )

      results = described_class.new(
        video,
        video_analysis,
        audio_analysis,
        [earlier_edl_event_response, later_edl_event_response],
        [],
      ).all_tracks_edl_events

      expect(results).to eq [
        EdlEvent.new(
          channel: "V",
          start_time: 0,
          timecode_in: "00:00:00:00",
          timecode_out: "00:00:01:00",
          duration: 1,
          source_file_name: "my_file.mp4",
          clip_name: "my_clip.mp4",
          description: "This is a great clip",
          matches: [],
        ),
        EdlEvent.new(
          channel: "A1",
          start_time: 100,
          timecode_in: "00:00:10:00",
          timecode_out: "00:00:11:00",
          duration: 1,
          source_file_name: "another_file.mp4",
          clip_name: "another_clip.mp4",
          description: "This is a great clip",
          matches: [],
        ),
      ]
    end
  end
end
