# TranscriptHighlight Model
class TranscriptHighlight < ApplicationRecord
  belongs_to :user
  belongs_to :respondent
  belongs_to :highlight_theme, optional: true
  belongs_to :master_section, optional: true

  has_attached_file :reel, validate_media_type: false
  do_not_validate_attachment_file_type :reel

  enum :reel_type, { audio: "audio", video: "video" }

  def media_type
    reel_type
  end

  def pending_highlights_for_same_video
    pending_tasks = SystemTask.where(status: "queued", task_type: "ReelCreation")
    pending_highlights = pending_tasks.collect { |x| x.metadata["transcript_highlight_id"] }.compact

    TranscriptHighlight.where(respondent_id:).where(id: pending_highlights)
  end

  def create_reel(system_task_id:)
    require "google/cloud/run/v2"

    highlight_respondent = respondent
    highlights_for_same_video = pending_highlights_for_same_video

    source_media_type = highlight_respondent.media_type

    self.reel_type = source_media_type
    save!

    source_media_path = if source_media_type == "video"
                          highlight_respondent.video_file.path
                        else
                          highlight_respondent.audio_file.path
                        end

    source_media_gcs_uri = "gs://sprint-qualplatform/#{source_media_path}"

    notification_url = "https://analysis.sprintstudio.ai/api/cloud_job_finish"
    error_notification_url = "https://analysis.sprintstudio.ai/api/cloud_job_error"

    client = Google::Cloud::Run::V2::Jobs::Client.new
    project_id = "norse-baton-398712"
    region = "asia-south1"
    parent = "projects/#{project_id}/locations/#{region}"
    job_name = "video-processor-job"

    # Grab all the queued system tasks
    if highlights_for_same_video.count > 1
      job_type = "CREATE_MULTIPLE_REELS"

      reel_payloads = highlights_for_same_video.map do |x|
        { transcript_highlight_id: x.id, start_timestamp: x.start, end_timestamp: x.end,
          output_gcs_uri: "gs://sprint-qualplatform/#{reel_path_for(x.id, source_media_type)}" }
      end
      reel_payloads.concat([{ transcript_highlight_id: id, start_timestamp: start, end_timestamp: self.end, source_media_type:,
                              output_gcs_uri: "gs://sprint-qualplatform/#{reel_path_for(id, source_media_type)}" }])
      reel_payloads.uniq!

      json_payload = {
        job_type:,
        system_task_id:,
        reel_payloads:,
        source_media_type:,
        source_media_gcs_uri:,
        notification_url:,
        error_notification_url:
      }.to_json
    else
      reel_start = start
      reel_end = self.end

      job_type = "CREATE_REEL"

      output_gcs_uri = "gs://sprint-qualplatform/#{reel_path_for(id, source_media_type)}"

      json_payload = {
        job_type:,
        system_task_id:,
        notification_url:,
        error_notification_url:,
        source_media_type:,
        source_media_gcs_uri:,
        output_gcs_uri:,
        transcript_highlight_id: id,
        start_timestamp: reel_start,
        end_timestamp: reel_end
      }.to_json
    end
    Rails.logger.debug("Reel Creation payload -> #{json_payload}")
    request = Google::Cloud::Run::V2::RunJobRequest.new(
      name: "#{parent}/jobs/#{job_name}",
      overrides: {
        container_overrides: [
          {
            args: [json_payload]
          }
        ]
      }
    )

    operation = client.run_job request
    Rails.logger.info "Started Cloud Run Job. Operation name: #{operation.name}"
  rescue Google::Cloud::Error => e
    Rails.logger.error "Failed to run Cloud Run Job: #{e.message}"
  end

  def reel_url_unsigned
    reel.url
  end

  def reel_url
    SprintGCS.signed_url(
      bucket_name: "sprint-qualplatform",
      file_path: reel.path
    )
  end

  def reel_available
    return false if reel_file_name.nil?

    true
  end

  def processing
    task = SystemTask.where(task_type: "ReelCreation").where("metadata @> ?",
                                                             { transcript_highlight_id: id }.to_json).last
    return false if task.nil?

    %w[queued running].include?(task.status.downcase)
  end

  def highlighted_by
    user.name
  end

  def verbose_to_text
    result = ""
    if manual
      content.split("\n").each do |sentence|
        result << "#{sentence}\n\n"
      end
    else
      mapped = verbose_text_to_mapped
      mapped.each do |row|
        result << "#{respondent.mapped_name(row[:speaker])}: #{row[:text]}\n\n"
      end
    end
    result
  end

  def ifw_verbose_to_mapped
    result = []
    current_speaker = nil
    current_speech = ""
    previous_text = ""

    sorted_transcript = content.sort_by { |x| x["timestamp"].first }
    sorted_transcript.each do |row|
      if current_speaker != row["speaker"]
        # Add the previous speaker's speech to the result, unless it's the first iteration
        result << { speaker: current_speaker, text: current_speech } unless current_speaker.nil?

        # Reset for new speaker
        current_speaker = row["speaker"]
        current_speech = ""
        previous_text = ""
      end

      # Construct the speech line from words and check for repetitions
      speech_line = row["text"]
      unless speech_line == previous_text
        current_speech << " #{speech_line}"
        previous_text = speech_line
      end
    end
    result << { speaker: current_speaker, text: current_speech } unless current_speaker.nil?
    result
  end

  def verbose_to_mapped
    first_row = content.first
    return ifw_verbose_to_mapped unless first_row.key?("end")

    result = []
    current_speaker = nil
    current_speech = ""
    previous_text = ""

    content.sort_by { |x| x["start"] }.each do |row|
      # Check if the speaker has changed
      if current_speaker != row["speaker"]
        # Add the previous speaker's speech to the result, unless it's the first iteration
        result << { speaker: current_speaker, text: current_speech } unless current_speaker.nil?

        # Reset for new speaker
        current_speaker = row["speaker"]
        current_speech = ""
        previous_text = ""
      end

      # Construct the speech line from words and check for repetitions
      speech_line = row["words"].map { |word| word["word"] }.join(" ")
      unless speech_line == previous_text
        current_speech << " #{speech_line}"
        previous_text = speech_line
      end
    end

    # Add the last speaker's speech to the result
    result << { speaker: current_speaker, text: current_speech } unless current_speaker.nil?
    result
  end

  def verbose_text_to_mapped
    return if content.blank?

    first_row = content.first
    return ifw_verbose_to_mapped unless first_row.key?("end")

    result = []
    current_speaker = nil
    current_speech = ""

    content.sort_by { |x| x["start"] }.each do |row|
      text = row["text"].to_s.strip
      next if text.empty?

      if current_speaker != row["speaker"]
        # Add the previous speaker's speech to the result
        result << { speaker: current_speaker, text: current_speech.strip } unless current_speaker.nil?

        current_speaker = row["speaker"]
        current_speech = text
      else
        current_speech << " #{text}"
      end
    end

    # Add the final speaker's speech
    result << { speaker: current_speaker, text: current_speech.strip } unless current_speaker.nil?
    result
  end

  private

  def reel_path_for(transcript_highlight_id, type)
    require "securerandom"
    id_partition = format("%09d", transcript_highlight_id).scan(/\d{3}/).join("/")

    uuid = SecureRandom.uuid

    "transcript_highlights/reels/#{id_partition}/original/reel_#{uuid}.#{type == 'video' ? 'mp4' : 'mp3'}"
  end
end
