# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


require "google/cloud/translate/v2/service"
require "google/cloud/translate/v2/translation"
require "google/cloud/translate/v2/detection"
require "google/cloud/translate/v2/language"

module Google
  module Cloud
    module Translate
      module V2
        ##
        # # Api
        #
        # Represents top-level access to the Google Cloud Translation API. Translation API supports more than one
        # hundred different languages, from Afrikaans to Zulu. Used in combination, this enables translation between
        # thousands of language pairs. Also, you can send in HTML and receive HTML with translated text back. You don't
        # need to extract your source text or reassemble the translated content.
        #
        # @see https://cloud.google.com/translation/docs/getting-started Cloud Translation API Quickstart
        #
        # @example
        #   require "google/cloud/translate/v2"
        #
        #   translate = Google::Cloud::Translate::V2.new
        #
        #   translation = translate.translate "Hello world!", to: "la"
        #
        #   translation.to_s #=> "Salve mundi!"
        #
        #   translation.from #=> "en"
        #   translation.origin #=> "Hello world!"
        #   translation.to #=> "la"
        #   translation.text #=> "Salve mundi!"
        #
        class Api
          ##
          # @private The Service object.
          attr_accessor :service

          ##
          # @private Creates a new Api instance.
          #
          # See {Google::Cloud.translate}
          def initialize service
            @service = service
          end

          ##
          # The Cloud Translation API project connected to.
          #
          # @example
          #   require "google/cloud/translate/v2"
          #
          #   translate = Google::Cloud::Translate::V2.new(
          #     project_id: "my-todo-project",
          #     credentials: "/path/to/keyfile.json"
          #   )
          #
          #   translate.project_id #=> "my-todo-project"
          #
          def project_id
            service.project_id
          end
          alias project project_id

          ##
          # Returns text translations from one language to another.
          #
          # @see https://cloud.google.com/translation/docs/translating-text#Translate Translating Text
          #
          # @param [String] text The text or texts to translate.
          # @param [String] to The target language into which the text should be translated. This is required. The value
          #   must be an [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code.
          # @param [String] from The source language of the text or texts. This is an [ISO
          #   639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) language code. This is optional.
          # @param [String] format The format of the text. Possible values include `:text` and `:html`. This is
          #   optional. The Translation API default is `:html`.
          # @param [String] model The model used by the service to perform the translation. Can be either `base` to use
          #   the Phrase-Based Machine Translation (PBMT) model, or `nmt` to use the Neural Machine Translation (NMT)
          #   model. The default is `nmt`.
          #
          #    If the model is `nmt`, and the requested language translation pair is not supported for the NMT model,
          #    then the request is translated using the PBMT model.
          #
          # @param [String] cid The customization id for translate. This is optional.
          #
          # @return [Translation, Array<Translation>] A single {Translation} object if just one text was given, or an
          #   array of {Translation} objects if multiple texts were given.
          #
          # @example
          #   require "google/cloud/translate/v2"
          #
          #   translate = Google::Cloud::Translate::V2.new
          #
          #   translation = translate.translate "Hello world!", to: "la"
          #
          #   translation.to_s #=> "Salve mundi!"
          #
          #   translation.detected? #=> true
          #   translation.from #=> "en"
          #   translation.origin #=> "Hello world!"
          #   translation.to #=> "la"
          #   translation.text #=> "Salve mundi!"
          #   translation.model #=> "base"
          #
          # @example Using the neural machine translation model:
          #   require "google/cloud/translate/v2"
          #
          #   translate = Google::Cloud::Translate::V2.new
          #
          #   translation = translate.translate "Hello world!",
          #                                     to: "la", model: "nmt"
          #
          #   translation.to_s #=> "Salve mundi!"
          #   translation.model #=> "nmt"
          #
          # @example Setting the `from` language.
          #   require "google/cloud/translate/v2"
          #
          #   translate = Google::Cloud::Translate::V2.new
          #
          #   translation = translate.translate "Hello world!",
          #                                     from: :en, to: :la
          #   translation.detected? #=> false
          #   translation.text #=> "Salve mundi!"
          #
          # @example Retrieving multiple translations.
          #   require "google/cloud/translate/v2"
          #
          #   translate = Google::Cloud::Translate::V2.new
          #
          #   translations = translate.translate "Hello my friend.",
          #                                      "See you soon.",
          #                                      from: "en", to: "la"
          #   translations.count #=> 2
          #   translations[0].text #=> "Salve amice."
          #   translations[1].text #=> "Vide te mox."
          #
          # @example Preserving HTML tags.
          #   require "google/cloud/translate/v2"
          #
          #   translate = Google::Cloud::Translate::V2.new
          #
          #   translation = translate.translate "<strong>Hello</strong> world!",
          #                                     to: :la
          #   translation.text #=> "<strong>Salve</strong> mundi!"
          #
          def translate *text, to: nil, from: nil, format: nil, model: nil, cid: nil
            return nil if text.empty?
            raise ArgumentError, "to is required" if to.nil?
            to = to.to_s
            from = from.to_s if from
            format = format.to_s if format
            text = Array(text).flatten
            gapi = service.translate text, to: to, from: from, format: format, model: model, cid: cid
            Translation.from_gapi_list gapi, text, to, from
          end

          ##
          # Detect the most likely language or languages of a text or multiple texts.
          #
          # @see https://cloud.google.com/translation/docs/detecting-language Detecting Language
          #
          # @param [String] text The text or texts upon which language detection should be performed.
          #
          # @return [Detection, Array<Detection>] A single {Detection} object if just one text was given, or an array
          #   of {Detection} objects if multiple texts were given.
          #
          # @example
          #   require "google/cloud/translate/v2"
          #
          #   translate = Google::Cloud::Translate::V2.new
          #
          #   detection = translate.detect "Hello world!"
          #   detection.language #=> "en"
          #   detection.confidence #=> 0.7100697
          #
          # @example Detecting multiple texts.
          #   require "google/cloud/translate/v2"
          #
          #   translate = Google::Cloud::Translate::V2.new
          #
          #   detections = translate.detect "Hello world!",
          #                                 "Bonjour le monde!"
          #   detections.count #=> 2
          #   detections.first.language #=> "en"
          #   detections.first.confidence #=> 0.7100697
          #   detections.last.language #=> "fr"
          #   detections.last.confidence #=> 0.40440267
          #
          def detect *text
            return nil if text.empty?
            text = Array(text).flatten
            gapi = service.detect text
            Detection.from_gapi gapi, text
          end

          ##
          # List the languages supported by the API. These are the languages to and from which text can be translated.
          #
          # @see https://cloud.google.com/translation/docs/discovering-supported-languages
          #   Discovering Supported Languages
          #
          # @param [String] language The language and collation in which the names of the languages are returned. If
          #   this is `nil` then no names are returned.
          #
          # @return [Array<Language>] An array of {Language} objects supported by the API.
          #
          # @example
          #   require "google/cloud/translate/v2"
          #
          #   translate = Google::Cloud::Translate::V2.new
          #
          #   languages = translate.languages
          #   languages.count #=> 104
          #
          #   english = languages.detect { |l| l.code == "en" }
          #   english.name #=> nil
          #
          # @example Get all languages with their names in French.
          #   require "google/cloud/translate/v2"
          #
          #   translate = Google::Cloud::Translate::V2.new
          #
          #   languages = translate.languages "fr"
          #   languages.count #=> 104
          #
          #   english = languages.detect { |l| l.code == "en" }
          #   english.name #=> "Anglais"
          #
          def languages language = nil
            language = language.to_s if language
            gapi = service.languages language
            Array(gapi["languages"]).map { |g| Language.from_gapi g }
          end
        end
      end
    end
  end
end
