# frozen_string_literal: true

require "em-http"
require "em_promise"
require "json"

class RevAi
	class Failed < StandardError; end

	def initialize(token: CONFIG[:rev_ai_token], logger: log)
		@token = token
		@log = logger
	end

	def stt(language, media_url, callback_url, **kwargs)
		req(
			:post,
			"https://api.rev.ai/speechtotext/v1/jobs",
			metadata: { media_url: media_url }.merge(kwargs).to_json,
			source_config: { url: media_url },
			notification_config: { url: callback_url },
			remove_disfluencies: language == "en",
			skip_diarization: true,
			language: language
		)
	end

	def stt_result(job, url)
		job = job["job"]
		return maybe_retry_as_en(job, url) if job["status"] == "failed"

		req(
			:get,
			"https://api.rev.ai/speechtotext/v1/jobs/#{job['id']}/transcript",
			accept: "text/plain"
		).then do |res|
			text = res.response.split("    ", 3)[2]&.strip.to_s
			job.merge("text" => text, "metadata" => JSON.parse(job["metadata"]))
		end
	end

	def language_id(media_url, callback_url, **kwargs)
		req(
			:post,
			"https://api.rev.ai/languageid/v1/jobs",
			metadata: { media_url: media_url }.merge(kwargs).to_json,
			source_config: { url: media_url },
			notification_config: { url: callback_url }
		)
	end

	def language_id_result(job)
		job = job["job"]
		return failed(job) if job["status"] == "failed"

		req(
			:get,
			"https://api.rev.ai/languageid/v1/jobs/#{job['id']}/result"
		).then do |res|
			json = JSON.parse(res.response)
			job.merge(json).merge("metadata" => JSON.parse(job["metadata"]))
		end
	end

protected

	def req(m, url, accept: nil, **kwargs)
		EM::HttpRequest.new(
			url, tls: { verify_peer: true }
		).public_send(
			"a#{m}",
			head: {
				"Authorization" => "Bearer #{@token}",
				"Content-Type" => "application/json",
				"Accept" => accept
			}, body: kwargs.to_json
		)
	end

	def failed(job)
		EMPromise.reject(Failed.new("#{job['failure']} #{job['failure_detail']}"))
	end

	def maybe_retry_as_en(job, url)
		return failed(job) if job["language"] == "en"

		metadata = JSON.parse(job["metadata"]).transform_keys(&:to_sym)
		return failed(job) if metadata[:retry]

		retry_as_en(metadata, url)
	end

	def retry_as_en(metadata, url)
		@log.info "Retry transcription as EN"
		stt("en", metadata[:media_url], url, **metadata.merge(retry: true)).then do
			{}
		end
	end
end
