package {{packageName}}

import com.codahale.metrics.*
import com.typesafe.config.ConfigFactory
import io.ktor.application.*
import io.ktor.client.HttpClient
import io.ktor.client.engine.apache.Apache
import io.ktor.config.HoconApplicationConfig
import io.ktor.features.*
import io.ktor.gson.GsonConverter
import io.ktor.http.ContentType
import io.ktor.locations.*
import io.ktor.metrics.*
import io.ktor.routing.*
import java.util.concurrent.*
{{#hasAuthMethods}}
import io.ktor.auth.*
import io.ktor.util.KtorExperimentalAPI
import org.openapitools.server.infrastructure.*
{{/hasAuthMethods}}
{{#generateApis}}
import {{apiPackage}}.*
{{/generateApis}}

{{#imports}}import {{import}}
{{/imports}}

@KtorExperimentalAPI
internal val settings = HoconApplicationConfig(ConfigFactory.defaultApplication(HTTP::class.java.classLoader))

object HTTP {
    val client = HttpClient(Apache)
}

@KtorExperimentalAPI
@KtorExperimentalLocationsAPI
fun Application.main() {
    install(DefaultHeaders)
    install(Metrics) {
        val reporter = Slf4jReporter.forRegistry(registry)
                .outputTo(log)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build()
        reporter.start(10, TimeUnit.SECONDS)
    }
{{#generateApis}}
    install(ContentNegotiation) {
        register(ContentType.Application.Json, GsonConverter())
    }
    {{#featureAutoHead}}
    install(AutoHeadResponse) // see http://ktor.io/features/autoheadresponse.html
    {{/featureAutoHead}}
    {{#featureConditionalHeaders}}
    install(ConditionalHeaders) // see http://ktor.io/features/conditional-headers.html
    {{/featureConditionalHeaders}}
    {{#featureHSTS}}
    install(HSTS, ApplicationHstsConfiguration()) // see http://ktor.io/features/hsts.html
    {{/featureHSTS}}
    {{#featureCORS}}
    install(CORS, ApplicationCORSConfiguration()) // see http://ktor.io/features/cors.html
    {{/featureCORS}}
    {{#featureCompression}}
    install(Compression, ApplicationCompressionConfiguration()) // see http://ktor.io/features/compression.html
    {{/featureCompression}}
    install(Locations) // see http://ktor.io/features/locations.html
    {{#hasAuthMethods}}
    install(Authentication) {
    {{#authMethods}}
        {{#isBasic}}
        basic("{{{name}}}") {
        validate { credentials ->
            // TODO: "Apply your basic authentication functionality."
            // Accessible in-method via call.principal<UserIdPrincipal>()
            if (credentials.name == "Swagger" && "Codegen" == credentials.password) {
                UserIdPrincipal(credentials.name)
            } else {
                null
            }
        }
        {{/isBasic}}
        {{#isApiKey}}
        // "Implement API key auth ({{{name}}}) for parameter name '{{{keyParamName}}}'."
        apiKeyAuth("{{{name}}}") {
            validate { apikeyCredential: ApiKeyCredential ->
                when {
                    apikeyCredential.value == "keyboardcat" -> ApiPrincipal(apikeyCredential)
                    else -> null
                }
            }
        }
        {{/isApiKey}}
        {{#isOAuth}}
            {{#bodyAllowed}}
            {{/bodyAllowed}}
            {{^bodyAllowed}}
        oauth("{{name}}") {
            client = HttpClient(Apache)
            providerLookup = { ApplicationAuthProviders["{{{name}}}"] }
            urlProvider = { _ ->
            // TODO: define a callback url here.
            "/"
            }
        }
            {{/bodyAllowed}}
        {{/isOAuth}}
    {{/authMethods}}
    }
    {{/hasAuthMethods}}
    install(Routing) {
    {{#apiInfo}}
    {{#apis}}
    {{#operations}}
        {{classname}}()
    {{/operations}}
    {{/apis}}
    {{/apiInfo}}
    }

{{/generateApis}}

    environment.monitor.subscribe(ApplicationStopping)
    {
        HTTP.client.close()
    }
}
