module Deliver
  # Helps new user quickly adopt Deliver
  class DeliverfileCreator

    # This method will ask the user what he wants to do
    # @param deliver_path (String) The path in which the Deliverfile should be created
    # @param project_name (String) The default name of the project, which is used in the generated Deliverfile
    def self.create(deliver_path, project_name = nil)
      deliver_file_path = [deliver_path, Deliver::Deliverfile::Deliverfile::FILE_NAME].join("/")
      raise "Deliverfile already exists at path '#{deliver_file_path}'. Run 'deliver' to use Deliver.".red if File.exists?(deliver_file_path)

      project_name ||= Dir.pwd.split("/").last

      if agree("Do you want Deliver to automatically create the Deliverfile for you based " + 
              "on your current app? (y/n)", true)

        puts "\n\nFirst, you need to login with your iTunesConnect credentials. ".yellow + 
          "\nThis is necessary to fetch the latest metadata from your app and use it to create a Deliverfile for you." + 
          "\nIf you have previously entered your credentials already, you will not be asked again."

        if Deliver::PasswordManager.shared_manager.username and Deliver::PasswordManager.shared_manager.password
          identifier = ''
          while identifier.length < 3
            identifier = ask("\nApp Identifier of your app (e.g. at.felixkrause.app_name): ")
          end

          self.create_based_on_identifier(deliver_path, identifier, project_name)
        else
          self.create_example_deliver_file(deliver_file_path, project_name)
        end
      else
        self.create_example_deliver_file(deliver_file_path, project_name)
      end
    end

    # This method is used, when the user does not want to automatically create the Deliverfile
    # @param path (String) The exact path (including the file name) in which the Deliverfile should be created
    # @param project_name (String) The default name of the project, which is used in the generated Deliverfile
    def self.create_example_deliver_file(path, project_name)
      example = File.read("#{gem_path}/lib/assets/DeliverfileExample")
      example.gsub!("[[APP_NAME]]", project_name)
      File.write(path, example)

      FileUtils.mkdir_p './screenshots/'

      puts "Successfully created new Deliverfile at '#{path}'".green
    end

    # This will download all the app metadata and store its data into JSON files
    # @param deliver_path (String) The directory in which the Deliverfile should be created
    # @param identifier (String) The app identifier we want to create Deliverfile based on
    # @param project_name (String) The default name of the project, which is used in the generated Deliverfile
    def self.create_based_on_identifier(deliver_path, identifier, project_name)
      app = Deliver::App.new(app_identifier: identifier)
      app.set_metadata_directory("/tmp") # we don't want to pollute the current folder
      app.metadata # this will download the latest app metadata
      
      file_path = [deliver_path, Deliver::Deliverfile::Deliverfile::FILE_NAME].join('/')
      json = generate_deliver_file(app, deliver_path, project_name)
      File.write(file_path, json)
      
      puts "Successfully created new Deliverfile at '#{file_path}'".green
    end

    private
      def self.gem_path
        if not Helper.is_test? and Gem::Specification::find_all_by_name('deliver').any?
          return Gem::Specification.find_by_name('deliver').gem_dir
        else
          return './'
        end
      end

      # This method takes care of creating a new 'deliver' folder, containg the app metadata 
      # and screenshots folders
      def self.generate_deliver_file(app, path, project_name)
        metadata_path = "#{path}/deliver/"
        FileUtils.mkdir_p metadata_path

        json = create_json_based_on_xml(app, metadata_path)
        
        meta_path = "#{metadata_path}metadata.json"
        File.write(meta_path, JSON.pretty_generate(json))
        puts "Successfully created new metadata JSON file at '#{meta_path}'".green

        # Add a README to the screenshots folder
        File.write("#{metadata_path}screenshots/README.txt", File.read("#{gem_path}/lib/assets/ScreenshotsHelp"))

        # Generate the final Deliverfile here
        deliver = File.read("#{gem_path}/lib/assets/DeliverfileDefault")
        deliver.gsub!("[[APP_IDENTIFIER]]", app.app_identifier)
        deliver.gsub!("[[APP_NAME]]", project_name)
        deliver.gsub!("[[APPLE_ID]]", app.apple_id.to_s)
        deliver.gsub!("[[EMAIL]]", PasswordManager.shared_manager.username)

        return deliver
      end

      # Access the app metadata and use them to create a finished Deliverfile
      def self.create_json_based_on_xml(app, path)
        json = {}
        # Access the app metadata and use them to create a finished Deliverfile
        app_name = app.metadata.information.each do |locale, current|
          current.each do |key, value|
            if value and value.kind_of?Hash # that does not apply for screenshots, which is an array
              current[key] = value[:value] 
            else
              current.delete(key)
            end
          end

          json[locale] = current

          # Create an empty folder for the screenshots too
          FileUtils.mkdir_p "#{path}screenshots/#{locale}/"
        end

        return json
      end
  end
end