class Jets::Application

def aws

def aws
  Jets::AwsInfo.new
end

def config

def config
  @config ||= ActiveSupport::OrderedOptions.new # dont use memoize since we reset @config later
end

def configs!

def configs!
  load_environments_config
  load_db_config
  set_iam_policy # relies on dependent values, must be called afterwards
  normalize_env_vars!
end

def configure(&block)

def configure(&block)
  instance_eval(&block) if block
end

def deprecated_configs_message

def deprecated_configs_message
  unless config.ruby.lazy_load.nil?
    puts "Detected config.ruby.lazy_load = #{config.ruby.lazy_load.inspect}".color(:yellow)
    puts "Deprecated: config.ruby.lazy_load".color(:yellow)
    puts "Gems are now bundled with with Lambda Layer and there's no need to lazy load them."
    puts "Please remove the config in your config/application.rb or config/environments files."
    puts "You can have Jets automatically do this by running:"
    puts "  jets upgrade"
  end
end

def each_app_autoload_path(expression)

def each_app_autoload_path(expression)
  Dir.glob(expression).each do |p|
    p.sub!('./','')
    yield(p) unless exclude_autoload_path?(p)
  end
end

def exclude_autoload_path?(path)

def exclude_autoload_path?(path)
  path =~ %r{app/javascript} ||
  path =~ %r{app/views} ||
  path =~ %r{/functions} # app and shared
end

def finish!

def finish!
  deprecated_configs_message
  load_inflections
  load_routes
  Jets::Controller::Rendering::RackRenderer.setup! # Sets up ActionView etc
  # Load libraries at the end to trigger onload so we can defined options in any order.
  # Only action_mailer library have been used properly this way so far.
  require 'action_mailer'
end

def internal_autoload_paths

def internal_autoload_paths
  internal = File.expand_path("../internal", __FILE__)
  paths = %w[
    app/controllers
    app/helpers
    app/jobs
    app/models
  ]
  paths.map { |path| "#{internal}/#{path}" }
end

def load_config_application

def load_config_application
  app_config = "#{Jets.root}/config/application.rb"
  load app_config # use load instead of require so reload_configs! works
end

def load_db_config

def load_db_config
  config.database = {}
  Jets::Dotenv.load!
  database_yml = "#{Jets.root}/config/database.yml"
  if File.exist?(database_yml)
    text = Jets::Erb.result(database_yml)
    db_config = YAML.load(text)
    config.database = db_config
  end
end

def load_default_config

def load_default_config
  @config = default_config # sets Jets.config.project_name by calling parse_project_name
  set_computed_configs! # things like project_namespace that need project_name
  Jets::Dotenv.load! # needs Jets.config.project_name when using ssm in dotenv files
  Jets.config.project_name = parse_project_name # Must set again because JETS_PROJECT_NAME is possible
  load_config_application # this overwrites Jets.config.project_name
end

def load_environments_config

def load_environments_config
  env_file = "#{Jets.root}/config/environments/#{Jets.env}.rb"
  if File.exist?(env_file)
    code = IO.read(env_file)
    instance_eval(code, env_file)
  end
end

def load_inflections

def load_inflections
  Jets::Inflections.load!
end

def load_routes(refresh: false)

def load_routes(refresh: false)
  @router = nil if refresh # clear_routes
  routes_file = "#{Jets.root}/config/routes.rb"
  return unless File.exist?(routes_file)
  if refresh
    load routes_file # always evaluate
  else
    require routes_file # evaluate once
  end
end

def normalize_env_vars!

Auto-fix it for convenience.
the correct AWS Environment.Variables path struture.
It is pretty easy to attempt to set environment variables without
def normalize_env_vars!
  environment = config.function.environment
  if environment and !environment.to_h.key?(:variables)
    config.function.environment = {
      variables: environment.to_h
    }
  end
end

def parse_project_name


Lets parse for the project name instead for now.

* forces us to rescue all exceptions, which is a big hammer
class twice when config is called when declaring a function
* double loading of shared resources: Jets::Stack.subclasses will have the same
Double evaling config/application.rb causes subtle issues:
def parse_project_name
  return ENV['JETS_PROJECT_NAME'] if ENV['JETS_PROJECT_NAME'] # override
  lines = IO.readlines("#{Jets.root}/config/application.rb")
  project_name_line = lines.find { |l| l =~ /config\.project_name.*=/ }
  project_name_line.gsub(/.*=/,'').strip.gsub(/["']/,'') # project_name
end

def reload_configs!

creation of the s3 bucket.
creation. This allows us to reference IAM policies configs that depend on the
After the mimimal template gets build, we need to reload it for the full stack
def reload_configs!
  # Tricky: reset only the things that depends on the minimal stack
  @config.iam_policy = nil
  configs!
end

def routes

for scaffolding to work.

Jets.application.routes.draw do

Naming it routes because config/routes.rb requires
def routes
  @router ||= Jets::Router.new
end

def set_computed_configs!

def set_computed_configs!
  # env_extra can be also be set with JETS_ENV_EXTRA.
  # JETS_ENV_EXTRA higher precedence than config.env_extra
  config.env_extra = ENV['JETS_ENV_EXTRA'] if ENV['JETS_ENV_EXTRA']
  # IE: With env_extra: project-dev-1
  #     Without env_extra: project-dev
  config.short_env = ENV_MAP[Jets.env.to_sym] || Jets.env
  # table_namespace does not have the env_extra, more common case desired.
  config.table_namespace = [config.project_name, config.short_env].compact.join('-')
  config.project_namespace = Jets.project_namespace
end

def set_iam_policy

def set_iam_policy
  config.iam_policy ||= self.class.default_iam_policy
  config.managed_policy_definitions ||= [] # default empty
end

def setup!

def setup!
  load_default_config
  autoload_paths = config.autoload_paths + config.extra_autoload_paths
  setup_auto_load_paths(autoload_paths)
end

def setup_auto_load_paths(autoload_paths=default_autoload_paths)

def setup_auto_load_paths(autoload_paths=default_autoload_paths)
  loader = Jets::Autoloaders.main
  autoload_paths.each do |path|
    next unless File.exist?(path)
    loader.push_dir(path)
  end
  loader.enable_reloading if Jets.env.development?
  loader.setup
end