module Deliver
  class AppMetadata
    #####################################################
    # @!group Screenshot related
    #####################################################

    # Removes all currently enabled screenshots for the given language.
    # @param (String) language The language, which has to be in this list: {FastlaneCore::Languages}.
    def clear_all_screenshots(language)
      raise AppMetadataParameterError.new(INVALID_LANGUAGE_ERROR) unless FastlaneCore::Languages::ALL_LANGUAGES.include?language

      update_localized_value('software_screenshots', {language => {}}) do |field, useless, language|
        field.children.remove # remove all the screenshots
      end
      information[language][:screenshots] = []
      true
    end

    # Appends another screenshot to the already existing ones
    # @param (String) language The language, which has to be in this list: {FastlaneCore::Languages}.
    # @param (Deliver::AppScreenshot) app_screenshot The screenshot you want to add to the app metadata.
    # @raise (AppMetadataTooManyScreenshotsError) When there are already 5 screenshots (MAXIMUM_NUMBER_OF_SCREENSHOTS).

    def add_screenshot(language, app_screenshot)
      raise AppMetadataParameterError.new(INVALID_LANGUAGE_ERROR) unless FastlaneCore::Languages::ALL_LANGUAGES.include?language

      create_locale_if_not_exists(language)

      # Fetch the 'software_screenshots' node (array) for the specific locale
      locales = self.fetch_value("//x:locale[@name='#{language}']")

      screenshots = self.fetch_value("//x:locale[@name='#{language}']/x:software_screenshots").first

      if not screenshots or screenshots.children.count == 0
        screenshots.remove if screenshots

        # First screenshot ever
        screenshots = Nokogiri::XML::Node.new('software_screenshots', @data)
        locales.first << screenshots

        node_set = Nokogiri::XML::NodeSet.new(@data)
        node_set << app_screenshot.create_xml_node(@data, 1)
        screenshots.children = node_set
      else
        # There is already at least one screenshot
        next_index = 1
        screenshots.children.each do |screen|
          if screen['display_target'] == app_screenshot.screen_size
            next_index += 1
          end
        end

        if next_index > MAXIMUM_NUMBER_OF_SCREENSHOTS
          raise AppMetadataTooManyScreenshotsError.new("Only #{MAXIMUM_NUMBER_OF_SCREENSHOTS} screenshots are allowed per language per device type (#{app_screenshot.screen_size})")
        end

        # Ready for storing the screenshot into the metadata.xml now
        screenshots.children.after(app_screenshot.create_xml_node(@data, next_index))
      end

      information[language][:screenshots] << app_screenshot

      app_screenshot.store_file_inside_package(@package_path)
    end

    # This method will clear all screenshots and set the new ones you pass
    # @param new_screenshots
    #   +code+
    #    {
    #     'de-DE' => [
    #       AppScreenshot.new('path/screenshot1.png', Deliver::ScreenSize::IOS_35),
    #       AppScreenshot.new('path/screenshot2.png', Deliver::ScreenSize::IOS_40),
    #       AppScreenshot.new('path/screenshot3.png', Deliver::ScreenSize::IOS_IPAD)
    #     ]
    #    }
    # This method uses {#clear_all_screenshots} and {#add_screenshot} under the hood.
    # @return [bool] true if everything was successful
    # @raise [AppMetadataParameterError] error is raised when parameters are invalid
    def set_all_screenshots(new_screenshots)
      error_text = "Please pass a hash, containing an array of AppScreenshot objects"
      raise AppMetadataParameterError.new(error_text) unless new_screenshots.kind_of?Hash

      new_screenshots.each do |key, value|
        if key.kind_of?String and value.kind_of?Array and value.count > 0 and value.first.kind_of?AppScreenshot

          self.clear_all_screenshots(key)

          value.each do |screen|
            add_screenshot(key, screen)
          end
        else
          raise AppMetadataParameterError.new(error_text)
        end
      end
      true
    end

    # Automatically add all screenshots contained in the given directory to the app.
    #
    # This method will automatically detect which device type each screenshot is.
    #
    # This will also clear all existing screenshots before setting the new ones.
    # @param (Hash) hash A hash containing a different path for each locale ({FastlaneCore::Languages::ALL_LANGUAGES})
    # @param (Bool) Use the framed screenshots? Only use it if you use frameit 2.0

    def set_screenshots_for_each_language(hash, use_framed = false)
      raise AppMetadataParameterError.new("Parameter needs to be an hash, containg strings with the new description") unless hash.kind_of?Hash
      hash.each do |language, current_path|
        resulting_path = "#{current_path}/**/*.{png,jpg,jpeg}"

        raise AppMetadataParameterError.new(INVALID_LANGUAGE_ERROR) unless FastlaneCore::Languages::ALL_LANGUAGES.include?language

        # https://stackoverflow.com/questions/21688855/
        # File::FNM_CASEFOLD = ignore case
        if Dir.glob(resulting_path, File::FNM_CASEFOLD).count == 0
          Helper.log.error("No screenshots found at the given path '#{resulting_path}'")
        else
          self.clear_all_screenshots(language)

          Dir.glob(resulting_path, File::FNM_CASEFOLD).sort.each do |path|
            # When frameit is enabled, we only want to upload the framed screenshots
            if use_framed
              # Except for Watch screenshots, they are okay without _framed
              is_apple_watch = ((AppScreenshot.new(path).screen_size == AppScreenshot::ScreenSize::IOS_APPLE_WATCH) rescue false)
              unless is_apple_watch
                next unless path.include?"_framed."
              end
            else
              next if path.include?"_framed."
            end

            begin
              add_screenshot(language, Deliver::AppScreenshot.new(path))
            rescue AppMetadataTooManyScreenshotsError => ex
              # We just use the first 5 ones
            end
          end
        end
      end

      true
    end

    # This method will run through all the available locales, check if there is
    # a folder for this language (e.g. 'en-US') and use all screenshots in there
    # @param (String) path A path to the folder, which contains a folder for each locale
    # @param (Bool) Use the framed screenshots? Only use it if you use frameit 2.0
    def set_all_screenshots_from_path(path, use_framed = false)
      raise AppMetadataParameterError.new("Parameter needs to be a path (string)") unless path.kind_of?String

      found = false
      FastlaneCore::Languages::ALL_LANGUAGES.each do |language|
        full_path = path + "/#{language}"
        if File.directory?(full_path)
          found = true
          set_screenshots_for_each_language({
            language => full_path
          }, use_framed)
        end
      end
      return found
    end
  end
end