# frozen_string_literal: true

module ShopifyCLI
  module Resources
    class EnvFile
      include SmartProperties
      FILENAME = ".env"
      KEY_MAP = {
        "SHOPIFY_API_KEY" => :api_key,
        "SHOPIFY_API_SECRET" => :secret,
        "SHOP" => :shop,
        "SCOPES" => :scopes,
        "HOST" => :host,
      }

      class << self
        def read(_directory = Dir.pwd)
          input = parse_external_env
          new(input)
        end

        def parse(directory)
          File.read(File.join(directory, FILENAME))
            .gsub("\r\n", "\n").split("\n").each_with_object({}) do |line, output|
            match = /\A([A-Za-z_0-9]+)\s*=\s*(.*)\z/.match(line)
            if match
              key = match[1]
              output[key] = case match[2]
              # Remove single quotes
              when /\A'(.*)'\z/ then match[2]
              # Remove double quotes and unescape string preserving newline characters
              when /\A"(.*)"\z/ then match[2].gsub('\n', "\n").gsub(/\\(.)/, '\1')
              else match[2]
              end
            end
            output
          end
        end

        def parse_external_env(directory = Dir.pwd)
          env_details = {}
          extra = {}
          parse(directory).each do |key, value|
            if KEY_MAP[key]
              env_details[KEY_MAP[key]] = value
            else
              extra[key] = value
            end
          end
          env_details[:extra] = extra
          env_details
        end
      end

      property :api_key, required: true
      property :secret, required: true
      property :shop
      property :scopes
      property :host
      property :extra, default: -> { {} }

      def to_h
        out = {}
        KEY_MAP.each do |key, value|
          out[key] = send(value).to_s if send(value)
        end
        extra.each do |key, value|
          out[key] = value.to_s
        end
        out
      end

      def write(ctx)
        spin_group = CLI::UI::SpinGroup.new
        spin_group.add(ctx.message("core.env_file.saving_header", FILENAME)) do |spinner|
          output = []
          KEY_MAP.each do |key, value|
            output << "#{key}=#{send(value)}" if send(value)
          end
          extra.each do |key, value|
            output << "#{key}=#{value}"
          end
          ctx.print_task(ctx.message("core.env_file.saving", FILENAME))
          ctx.write(FILENAME, output.join("\n") + "\n")
          spinner.update_title(ctx.message("core.env_file.saved", FILENAME))
        end
        spin_group.wait
      end

      def update(ctx, field, value)
        self[field] = value
        write(ctx)
      end
    end
  end
end