require "athena-routing"

module CrystalGauntlet::Server
  class GDHandler
    include HTTP::Handler

    def call(context : HTTP::Server::Context)
      # expunge trailing slashes
      path = context.request.path.chomp("/")

      path = path.sub(config_get("general.append_path").as(String | Nil) || "", "")

      body = context.request.body

      if CrystalGauntlet.endpoints.has_key?(path) && context.request.method == "POST" && body
        func = CrystalGauntlet.endpoints[path]
        begin
          value = func.call(context)
        rescue err
          LOG.error { "error while handling #{path.colorize(:white)}:" }
          LOG.error { err.to_s }
          is_relevant = true
          err.backtrace.each do |str|
            # this is a hack. Oh well
            if str.starts_with?("src/crystal-gauntlet.cr") || (!is_relevant)
              is_relevant = false
            else
              LOG.error {"  #{str}"}
            end
          end
          context.response.content_type = "text/plain"
          context.response.respond_with_status(500, "-1")
        else
          max_size = 2048

          value_displayed = value
          if value.size > max_size
            value_displayed = value[0..max_size] + ("…".colorize(:dark_gray).to_s)
          end
          LOG.debug { "-> ".colorize(:green).to_s + value_displayed }

          context.response.content_type = "text/plain"
          # to let endpoints manually write to IO
          if value != ""
            context.response.print value
          end
        end
      else
        call_next(context)
      end
    end
  end

  def self.run()
    template_handler = ART::RoutingHandler.new

    CrystalGauntlet.template_endpoints.each do |key, handler|
      template_handler.add(
        key[:name],
        ART::Route.new(
          key[:path],
          methods: key[:methods]
        )
      ) { |ctx, params| handler.call(ctx, params) }
    end

    server = HTTP::Server.new([
      HTTP::LogHandler.new,
      HTTP::StaticFileHandler.new("public/", fallthrough: true, directory_listing: false),
      HTTP::StaticFileHandler.new((DATA_FOLDER / "songs").to_s, fallthrough: true, directory_listing: false),
      GDHandler.new,
      template_handler.compile
    ])

    listen_on = URI.parse(ENV["LISTEN_ON"]? || "http://localhost:8080").normalize

    case listen_on.scheme
    when "http"
      server.bind_tcp(listen_on.hostname.not_nil!, listen_on.port.not_nil!)
    when "unix"
      server.bind_unix(listen_on.to_s.sub("unix://",""))
    end

    check_server_length(false)

    Reupload.init()
    Ranks.init()

    @@up_at = Time.utc
    LOG.notice { "Listening on #{listen_on.to_s.colorize(:white)}" }
    server.listen
  end
end
