class ApiController < ApplicationController
  skip_before_action :verify_authenticity_token

  def temp_l
    #@user = User.find_by(email: params[:email])
    #sign_in @user
    #redirect_to root_url
  end

  def cloud_job_finish
    if params[:key] != Rails.application.credentials.sprint_api_auth.to_s
      Rails.logger.fatal("[GCP] Upload with unauthorized key")
      return render json: { status: "error", message: "Invalid Key" },
                    status: :unauthorized
    end

    task = begin
      SystemTask.find(params[:system_task_id])
    rescue StandardError
      nil
    end

    return if task.nil?

    case task&.task_type
    when "VideoConversion"
      update_audio_file(params[:respondent_id], params[:audio_gcs_uri], task)
    when "ReelCreation"
      update_reel(params[:transcript_highlight_id], params[:reel_gcs_uri], task)
    when "StitchedReelCreation"
      update_stitched_reel(params[:reel_id], params[:reel_type], params[:stitched_reel_gcs_uri], task)
    end
  end

  def cloud_job_error
    if params[:key] != Rails.application.credentials.sprint_api_auth.to_s
      Rails.logger.fatal("[REELS] Upload with unauthorized key")
      return render json: { status: "error", message: "Invalid Key" },
                    status: :unauthorized
    end

    task = begin
      SystemTask.find(params[:system_task_id])
    rescue StandardError
      nil
    end

    return if task.nil?

    case task&.task_type
    when "VideoConversion"
      md = task&.metadata&.with_indifferent_access
      Rails.logger.error "[GCP] Failed to save audio file for respondent: #{md[:respondent_id]}"
      TeamsAlertJob.perform_later(message: "[GCP] Failed to save audio file for respondent: #{md[:respondent_id]}")
      task&.update(running: false, status: "error")
      head :ok
    when "ReelCreation"
      md = task&.metadata&.with_indifferent_access
      Rails.logger.error "[GCP] Failed to save audio reel for transcript highlight: #{md[:transcript_highlight_id]}"
      TeamsAlertJob.perform_later(message: "[GCP] Failed to Failed to save audio reel for transcript highlight: #{md[:transcript_highlight_id]}")
      task&.update(running: false, status: "error")
      head :ok
    when "StitchedReelCreation"
      md = task&.metadata&.with_indifferent_access
      Rails.logger.error "[GCP] Failed to stitch reel: #{md[:reel_id]}"
      TeamsAlertJob.perform_later(message: "[GCP] Failed to stitch reel: #{md[:reel_id]}")
      task&.update(running: false, status: "error")
      head :ok
    end
  end

  def secure_login
    user = User.user_from_encrypted_link(params[:key])
    raise ActionController::RoutingError, "Forbidden" unless user

    sign_in user
    project = user.projects.last
    redirect_to projects_path if project.nil?

    redirect_to user.projects.last
  end

  def report_reel_error
    transcript_highlight_id = params[:transcript_highlight_id]
    task = SystemTask.where(metadata: { "transcript_highlight_id" => transcript_highlight_id }, status: %w[running queued],
                            task_type: "ReelCreator").first
    if task
      task.status = "error"
      task.save
    end
    head :ok
  end

  def reel_url
    highlight = TranscriptHighlight.find(params[:id])
    return render json: { url: highlight.reel_url } if highlight.respondent.visible_to?(current_user)

    render json: { url: "" }
  end

  def map_reduce_payload
    if params[:key] == Rails.application.credentials.sprint_api_map_reduce_auth.to_s
      respondent = Respondent.find(params[:id])
      return render json: { transcript: respondent.full_text }
    end
    render json: { status: "error" }
  end

  def map_reduce_answers
    qq = QuantifiableQuestion.find(params[:id])
    json = params[:mapped_answers]
    answers = JSON.parse(json)
    answers.each do |k, v|
      v = v.gsub("```json", "")
      v = v.gsub("```", "")
      answers[k] = JSON.parse(v)
    end
    qq.answer = answers
    qq.save

    if SystemTask.where(status: "queued", task_type: "QuantifiableQuestion").count.positive?
      task = SystemTask.where(task_type: "QuantifiableQuestion").last
      SystemTask.execute_next_task!(task_class: task.task_class)
    end

    render json: { status: "ok" }
  end

  def rate_insight
    @interview_insight = InterviewInsight.find(params[:id])
    @interview_insight.score = if @interview_insight.score == params[:score].to_i
                                 0
                               else
                                 params[:score]
                               end
    @interview_insight.save
    respond_to do |format|
      format.turbo_stream do
        render turbo_stream: turbo_stream.replace("vote-#{@interview_insight.id}", partial: "respondents/vote_buttons",
                                                                                   locals: { i: @interview_insight })
      end
    end
  end

  def signal_transcriber_ready
    Rails.logger.fatal("**************** TRANSCRIBER READY ****************")
    render json: { status: "ok" }
  end

  def instance_state
    CloudServices.set_instance_state("stopped")
    render json: { status: "ok" }
  end

  def instance_details
    CloudServices.set_instance_state("running")
    CloudServices.set_instance_ip(params[:ip_address])
    CloudServices.set_instance_name(params[:name])
    CloudServices.set_instance_zone(params[:zone])
    render json: { status: "ok" }
  end

  def update_task_status
    task = SystemTask.find(params[:id])
    task.status = params[:status]

    if task.task_type == "WxTranscribe" || task.task_type == "TranscribeV2"
      update_transcribing_progress(task, params[:status],
                                   task.metadata["respondent_id"])
    elsif task.task_type == "TranscribeV5"
      update_sarvam_progress(task, params[:status],
                             task.metadata["respondent_id"])
    end

    task.running = false if begin
      task.status.downcase.include?("fail") || task.status.downcase.include?("error")
    rescue StandardError
      false
    end

    task.running = false if begin
      task.status.downcase.include?("complete")
    rescue StandardError
      false
    end
    task.save
    SystemTask.execute_next_task!(task_class: task.task_class) if task.status.downcase.include?("error") || task.status.downcase.include?("fail")
    render json: { status: "OK" }
  end

  def transcript_data
    respondent = Respondent.find(params[:conversation_id])
    Rails.logger.fatal("Transcript data is: #{params[:transcript]}")
    transcript = JSON.parse params[:transcript]
    WhisperTranscript.create!(respondent_id: respondent.id, verbose_json: transcript)
    if SystemTask.where(status: "queued", task_type: "WxTranscribe").count.zero?
      # CloudServices.stop_instance
    else
      task = SystemTask.where(task_type: "WxTranscribe").last
      SystemTask.execute_next_task!(task_class: task.task_class)
    end
    render json: { status: "ok" }
  end

  def transcript_data_v2
    respondent = Respondent.find(params[:conversation_id])
    Rails.logger.fatal("Transcript data is: #{params[:transcript]}")

    transcript = JSON.parse params[:transcript]
    clean_transcript = Respondent.format_transcript(transcript)
    Rails.logger.fatal("V2 Clean Transcript  : #{clean_transcript.class}")

    WhisperTranscript.create!(respondent_id: respondent.id, verbose_json: clean_transcript)

    if SystemTask.where(status: "queued", task_type: "TranscribeV2").count.zero?
      # CloudServices.stop_instance
    else
      task = SystemTask.where(task_type: "TranscribeV2").last
      SystemTask.execute_next_task!(task_class: task.task_class)
    end
    render json: { status: "ok" }
  end

  def gladia_transcript
    transcript_id = params.dig(:payload, :id)
    if transcript_id
      task = SystemTask.where(request_id: transcript_id).first
      if task
        respondent_id = task.metadata["respondent_id"]
        if respondent_id
          respondent = Respondent.find(respondent_id)
          Gladia.retrieve(respondent:, id: transcript_id, translated: respondent.translate)
          task.running = false
          task.status = "complete"
          task.save!
          update_transcribing_progress(task, "complete", respondent.id)
          SystemTask.execute_next_task!(task_class: task.task_class)
        end
      end
    end
    head :ok
  end

  def deepgram_transcript
    # TODO: Validate dg-token header
    respondent = Respondent.find(params[:id])
    if params[:results]
      clean_transcript = Respondent.format_deepgram_result(params[:results].to_unsafe_h)
      Rails.logger.info("Clean: #{clean_transcript}")
      WhisperTranscript.create!(respondent_id: respondent.id, verbose_json: clean_transcript) unless clean_transcript.empty?
      Rails.logger.info("TranscribeV3 - Transcription Received - ")

      task = SystemTask.where(task_type: "TranscribeV3").where("metadata @> ?",
                                                               { respondent_id: respondent.id }.to_json).last
      task.running = false
      task.status = "complete"
      task.save!
      update_transcribing_progress(task, "complete", respondent.id)
      SystemTask.execute_next_task!(task_class: task.task_class)
    else
      Rails.logger.fatal("DEEPGRAM: #{params.to_unsafe_h}")
    end
    render json: { status: "ok" }
  end

  def sarvam_transcript
    if params[:api_key] != Rails.application.credentials.sprint_api_auth.to_s
      Rails.logger.fatal("[TranscribeV5] Upload with unauthorized key")
      return render json: { status: "error", message: "Invalid Key" },
                    status: :unauthorized
    end

    respondent = Respondent.find(params[:conversation_id])
    request_id = params[:job_id]
    Rails.logger.fatal("Transcript data is: #{params[:transcript]}")
    transcript = JSON.parse params[:transcript]
    WhisperTranscript.create!(respondent_id: respondent.id, verbose_json: transcript, request_id:)
    if SystemTask.where(status: "queued", task_type: "TranscribeV5").count.positive?
      task = SystemTask.where(task_type: "TranscribeV5").last
      SystemTask.execute_next_task!(task_class: task.task_class)
    end
    render json: { status: "ok" }
  end

  def save_response
    begin
      ir = InsightResponse.create!(
        json: JSON.parse(params[:json]),
        respondent_id: params[:respondent_id].to_i,
        whisper_version: params[:version].to_i,
        insights_report_id: params[:insights_report_id],
        from_whisper: params[:whisper] == "true"
      )
      ir.generate_insights
    rescue StandardError => e
      Rails.logger.fatal("Error: #{e.inspect}")
      Rails.logger.fatal("Error: #{e.backtrace}")
    end
    render json: { status: "ok" }
  end

  def create_insight
    InterviewInsight.create!(
      respondent_id: params[:respondent_id],
      interview_question_id: params[:interview_question_id],
      insights_report_id: params[:insights_report_id],
      from_whisper: params[:whisper],
      answer: params[:answer]
    )
    render json: { status: "ok", data: {} }
  end

  def update_sarvam_progress(task, status, respondent_id)
    case status&.downcase
    when "queued", "running", "downloading"
      task&.set_progress!(progress: 0, org_id: task.user.organization_id, metadata: { respondent_id: })
    when "converting"
      task&.set_progress!(progress: 25, org_id: task.user.organization_id, metadata: { respondent_id: })
    when "splitting"
      task&.set_progress!(progress: 50, org_id: task.user.organization_id, metadata: { respondent_id: })
    when "transcribing"
      task&.set_progress!(progress: 75, org_id: task.user.organization_id, metadata: { respondent_id: })
    when "complete"
      task&.set_progress!(progress: 100, org_id: task.user.organization_id, metadata: { respondent_id: })
    end
  end

  def update_transcribing_progress(task, status, respondent_id)
    case status&.downcase
    when "queued", "running", "downloading"
      task&.set_progress!(progress: 0, org_id: task.user.organization_id, metadata: { respondent_id: })
    when "converting"
      task&.set_progress!(progress: 10, org_id: task.user.organization_id, metadata: { respondent_id: })
    when "transcribing"
      task&.set_progress!(progress: 25, org_id: task.user.organization_id, metadata: { respondent_id: })
    when "cleaning"
      task&.set_progress!(progress: 35, org_id: task.user.organization_id, metadata: { respondent_id: })
    when "aligning"
      task&.set_progress!(progress: 50, org_id: task.user.organization_id, metadata: { respondent_id: })
    when "diarizing"
      task&.set_progress!(progress: 75, org_id: task.user.organization_id, metadata: { respondent_id: })
    when "complete"
      task&.set_progress!(progress: 100, org_id: task.user.organization_id, metadata: { respondent_id: })
    end
  end

  private

  def update_audio_file(respondent_id, gcs_uri, task)
    require "google/cloud/storage"

    respondent = Respondent.find_by(id: respondent_id)
    if respondent.nil?
      Rails.logger.error "[GCP] Respondent - #{respondent_id} was deleted during video processing."
      TeamsAlertJob.perform_later(message: "[GCP] Respondent - #{respondent_id} was deleted during video processing.")
      task&.update(running: false, status: "error")
      head :ok
    elsif gcs_uri.present?
      begin
        object_path = gcs_uri.gsub("gs://sprint-qualplatform/", "")
        storage = Google::Cloud::Storage.new(
          project_id: Rails.application.credentials.gcs.project
        )
        bucket = storage.bucket("sprint-qualplatform")
        file = bucket.file(object_path)
        respondent.audio_file_file_name = File.basename(gcs_uri)
        respondent.audio_file_file_size = file.size
        respondent.audio_file_content_type = file.content_type
        respondent.audio_file_updated_at = file.updated_at
        respondent.save
        Rails.logger.info("Saved Respondent #{respondent_id} audio file - #{gcs_uri}")
        task&.update(running: false, status: "complete")
        head :ok
      rescue StandardError => e
        Rails.logger.error "[GCP] Failed to save audio file for respondent #{respondent_id}: #{e.message}"
        TeamsAlertJob.perform_later(message: "[GCP] Failed to save audio file for respondent #{respondent_id}: #{e.message}")
        task&.update(running: false, status: "error")
        head :ok
      end
    else
      Rails.logger.error "[GCP] No audio file provided for respondent #{respondent_id}"
      TeamsAlertJob.perform_later(message: "[GCP] No audio file provided for respondent #{respondent_id}")
      task&.update(running: false, status: "error")
      head :ok
    end

    SystemTask.execute_next_task!(task_class: task&.task_class) if task
  end

  def update_reel(transcript_highlight_id, gcs_uri, task)
    require "google/cloud/storage"

    transcript_highlight = TranscriptHighlight.find_by(id: transcript_highlight_id)
    if transcript_highlight.nil?
      Rails.logger.error "[GCP] Transcript Highlight - #{transcript_highlight_id} was deleted during reel generation."
      TeamsAlertJob.perform_later(message: "[GCP] Transcript Highlight - #{transcript_highlight_id} was deleted during reel generation.")
      task&.update(running: false, status: "error")
      head :ok
    elsif gcs_uri.present?
      begin
        object_path = gcs_uri.gsub("gs://sprint-qualplatform/", "")
        storage = Google::Cloud::Storage.new(
          project_id: Rails.application.credentials.gcs.project
        )
        bucket = storage.bucket("sprint-qualplatform")
        file = bucket.file(object_path)

        transcript_highlight.reel_file_name = File.basename(gcs_uri)
        transcript_highlight.reel_file_size = file.size
        transcript_highlight.reel_content_type = file.content_type
        transcript_highlight.reel_updated_at = file.updated_at
        transcript_highlight.save

        correct_system_task_id = SystemTask.where(task_type: "ReelCreation")
                                           .where(metadata: { "transcript_highlight_id" => transcript_highlight_id }).first&.id
        if correct_system_task_id != task&.id && !correct_system_task_id.nil? && task.metadata["transcript_highlight_id"] != transcript_highlight_id
          Rails.logger.info("[TASKS] Updating multiple reel system task id: #{correct_system_task_id}")
          task = SystemTask.find(correct_system_task_id)
        end
        task&.update(running: false, status: "complete")
        task&.set_progress!(progress: 100,
                            org_id: task.user.organization_id,
                            metadata: {
                              highlight: transcript_highlight.as_json(
                                methods: %i[
                                  processing reel_available reel_url_unsigned verbose_to_text media_type
                                ]
                              ),
                              type: "transcript_highlight_job"
                            })
        head :ok
      rescue StandardError => e
        Rails.logger.error "[GCP] Failed to save reel for TranscriptHighlight #{transcript_highlight_id}: #{e.message}"
        TeamsAlertJob.perform_later(message: "[GCP] Failed to save reel for TranscriptHighlight #{transcript_highlight_id}: #{e.message}")
        task&.update(running: false, status: "error")
        head :ok
      end
    else
      Rails.logger.error "[GCP] No reel provided for TranscriptHighlight: #{transcript_highlight_id}"
      TeamsAlertJob.perform_later(message: "[GCP] No reel provided for TranscriptHighlight: #{transcript_highlight_id}")
      task&.update(running: false, status: "error")
      head :ok
    end

    SystemTask.execute_next_task!(task_class: task&.task_class) if task
  end

  def update_stitched_reel(reel_id, reel_type, gcs_uri, task)
    require "google/cloud/storage"

    reel = Reel.find_by(id: reel_id)
    if reel.nil?
      Rails.logger.error "[GCP] Stitched Reel - #{reel_id} was deleted during stitched reel generation."
      TeamsAlertJob.perform_later(message: "[GCP] Stitched Reel - #{reel_id} was deleted during stitched reel generation.")
      task&.update(running: false, status: "complete")
      head :ok
    elsif gcs_uri.present?
      begin
        object_path = gcs_uri.gsub("gs://sprint-qualplatform/", "")
        storage = Google::Cloud::Storage.new(
          project_id: Rails.application.credentials.gcs.project
        )
        bucket = storage.bucket("sprint-qualplatform")
        file = bucket.file(object_path)

        if reel_type == "video"
          reel.video_file_name = File.basename(gcs_uri)
          reel.video_file_size = file.size
          reel.video_content_type = file.content_type
          reel.video_updated_at = file.updated_at
        else
          reel.audio_file_name = File.basename(gcs_uri)
          reel.audio_file_size = file.size
          reel.audio_content_type = file.content_type
          reel.audio_updated_at = file.updated_at
        end

        reel.save

        correct_system_task_id = SystemTask.where(task_type: "StitchedReelCreation").where(metadata: { "reel_id" => reel_id }).first&.id
        if correct_system_task_id != task&.id && !correct_system_task_id.nil? && task.metadata["reel_id"] != reel_id
          Rails.logger.info("[TASKS] Updating stitched reel system task id: #{correct_system_task_id}")
          task = SystemTask.find(correct_system_task_id)
        end
        task&.update(running: false, status: "complete")
        task&.set_progress!(progress: 100,
                            org_id: task.user.organization_id,
                            metadata: { reel: reel.as_json(methods: %i[video_url_unsigned audio_url_unsigned reel_available processing]),
                                        respondent_category_id: task.metadata["respondent_category_id"],
                                        type: "reel_stitching_job" })
        head :ok
      rescue StandardError => e
        Rails.logger.error "[GCP] Failed to save reel for Stitched Reel #{reel_id}: #{e.message}"
        TeamsAlertJob.perform_later(message: "[GCP] Failed to save reel for Stitched Reel #{reel_id}: #{e.message}")
        task&.update(running: false, status: "error")
        head :ok
      end
    else
      Rails.logger.error "[GCP] No reel provided for Stitched Reel: #{reel_id}"
      TeamsAlertJob.perform_later(message: "[GCP] No reel provided for Stitched Reel: #{reel_id}")
      task&.update(running: false, status: "error")
      head :ok
    end

    SystemTask.execute_next_task!(task_class: task&.task_class) if task
  end
end
