module Aigu
  class AndroidImporter < Importer
    ARRAY_REGEX = /__ARRAY_ITEM__#(?<index>\d+)$/
    TYPE_REGEX = /__@TYPE_(?<type_key>.+)$/

    def process!
      puts "Generating Android XML files in `#{@output_directory}` based on Accent-generated `#{@input_file}` file"
      puts '---'

      parse_json
      @blob = split_res_types(@object)
      write_xml_files

      puts '---'
      puts 'Done'
    end

  protected

    def parse_json
      json = File.read(@input_file)
      @object = JSON.parse(json)
      @object = expand_content_values(@object)
      @object = escape_special_characters(@object)
    end

    def write_xml_files
      @blob.each_pair do |type, hash|
        # TODO: add locale to filename
        qualifier = type.gsub(/_/, '-')
        if qualifier != ''
          qualifier.prepend('-')
        end
        if @locale
          language = '-' + @locale
        else
          language = ''
        end

        file_path = File.join(@output_directory, "values#{language}#{qualifier}", 'strings.xml')
        puts "Generating #{file_path}"
        FileUtils.mkdir_p(File.dirname(file_path))

        File.open(file_path, 'w+:bom|utf-8') do |file|
          file << res_to_xml(hash)
        end
      end
    end

    # TODO: Use XML tooling
    def res_to_xml(content)
      xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
      xml << "<resources>\n"

      content.each_pair do |key, value|
        if value.is_a?(Array)
          xml << '    <string-array name=' << key.encode(xml: :attr) << ">\n"
          value.each do |item|
            xml << '        <item>' << item.encode(xml: :text) << "</item>\n" if item
          end
          xml << "    </string-array>\n"
        elsif value.is_a?(String)
          xml << '    <string name=' << key.encode(xml: :attr) << '>' << value.encode(xml: :text) << "</string>\n"
        end
      end

      xml << "</resources>\n"
      xml
    end

    def localize_content_keys(content)
      content.reduce({}) do |memo, (key, value)|
        localized_key = key.gsub(/^([^|]+)\|/, "\\1.#{@locale}|#{@locale}.")
        memo.merge localized_key => value
      end
    end

    def expand_content_values(content)
      content.each_with_object({}) do |(key, value), memo|
        match_data = key.match(ARRAY_REGEX)

        if match_data
          canonical_key = key.gsub(ARRAY_REGEX, '')
          value_index = match_data[:index].to_i
          memo[canonical_key] ||= []
          memo[canonical_key][value_index] = sanitize_string_to_value(value)
        else
          memo[key] = sanitize_string_to_value(value)
        end
      end
    end

    def escape_special_characters(content)
      content.each_with_object({}) do |(key, value), memo|
        if value.is_a?(Array)
          memo[key] = value.map { |s| escape_string_special_characters(s) }
        else
          memo[key] = escape_string_special_characters(value)
        end
      end
    end

    def escape_string_special_characters(string)
      string.gsub("'", "\\\\'")
    end

    def split_res_types(content)
      res_types = {}

      content.each_pair do |key, value|
        match_data = key.match(TYPE_REGEX)
        if match_data
          canonical_key = key.gsub(TYPE_REGEX, '')
          res_type = match_data[:type_key]
        else
          canonical_key = key
          res_type = ''
        end
        res_types[res_type] ||= {}
        res_types[res_type][canonical_key] = value
      end

      res_types
    end

    def sanitize_string_to_value(string)
      case string
        when '___TRUE___'
          true
        when '___FALSE___'
          false
        when '___NULL___'
          nil
        else
          string
      end
    end
  end
end