require 'plist'

module Fastlane
  module Actions
    class UpdateUrlSchemesAction < Action
      def self.run(params)
        path = params[:path]
        url_schemes = params[:url_schemes]
        update_url_schemes = params[:update_url_schemes]

        hash = Plist.parse_xml(path)

        # Create CFBundleURLTypes array with empty scheme if none exist
        unless hash['CFBundleURLTypes']
          hash['CFBundleURLTypes'] = [{
            'CFBundleTypeRole' => 'Editor',
            'CFBundleURLSchemes' => []
          }]
        end

        # Updates schemes with update block if exists
        # Else updates with array of strings if exist
        # Otherwise shows error to user
        if update_url_schemes
          new_schemes = update_url_schemes.call(hash['CFBundleURLTypes'].first['CFBundleURLSchemes'])

          # Verify array of strings
          string = "The URL schemes must be an array of strings, got '#{new_schemes}'."
          verify_schemes!(new_schemes, string)

          hash['CFBundleURLTypes'].first['CFBundleURLSchemes'] = new_schemes
        elsif url_schemes
          hash['CFBundleURLTypes'].first['CFBundleURLSchemes'] = url_schemes
        else
          UI.user_error!("No `url_schemes` or `update_url_schemes` provided")
        end
        File.write(path, Plist::Emit.dump(hash))
      end

      def self.verify_schemes!(url_schemes, error_message)
        UI.user_error!(error_message) unless url_schemes.kind_of?(Array)

        url_schemes.each do |url_scheme|
          UI.user_error!(error_message) unless url_scheme.kind_of?(String)
        end
      end

      def self.description
        'Updates the URL schemes in the given Info.plist'
      end

      def self.available_options
        [
          FastlaneCore::ConfigItem.new(
            key: :path,
            env_name: 'FL_UPDATE_URL_SCHEMES_PATH',
            description: 'The Plist file\'s path',
            is_string: true,
            optional: false,
            verify_block: proc do |path|
              UI.user_error!("Could not find plist at path '#{path}'") unless File.exist?(path)
            end
          ),

          FastlaneCore::ConfigItem.new(
            key: :url_schemes,
            env_name: "FL_UPDATE_URL_SCHEMES_SCHEMES",
            description: 'The new URL schemes',
            is_string: false,
            optional: true,
            verify_block: proc do |url_schemes|
              string = "The URL schemes must be an array of strings, got '#{url_schemes}'."
              verify_schemes!(url_schemes, string)
            end
          ),

          FastlaneCore::ConfigItem.new(key: :update_url_schemes,
            description: "Block that is called to update schemes with current schemes passed in as parameter",
            optional: true,
            is_string: false)
        ]
      end

      def self.details
        [
          "This action allows you to update the URL schemes of the app before building it.",
          "For example, you can use this to set a different URL scheme for the alpha or beta version of the app."
        ].join("\n")
      end

      def self.output
        []
      end

      def self.authors
        ['kmikael']
      end

      def self.is_supported?(platform)
        [:ios, :mac].include?(platform)
      end

      def self.example_code
        [
          'update_url_schemes(
            path: "path/to/Info.plist",
            url_schemes: ["com.myapp"]
          )',
          'update_url_schemes(
            path: "path/to/Info.plist",
            update_url_schemes: proc do |schemes|
              schemes + ["anotherscheme"]
            end
          )'
        ]
      end

      def self.category
        :project
      end
    end
  end
end
