{{>header}}

import { Express, Request, Response } from 'express'
import passport from 'passport'
import multer from 'multer'
import * as t from './types'
import * as v from '../../validation'
{{#if containsMultipartOperation}}
import * as f from '../../impl/helpers/{{lowerCase name}}MultipartHelper'
{{/if}}
import { Api } from '../../models'

export default function(app: Express, impl: t.{{className name}}Api) {
	{{#each operations}}
	app.{{lowerCase httpMethod}}(
		{{{stringLiteral (pathTemplate fullPath)}}},
		{{>frag/apiSecurityRequirements}}
		{{#if (operationSupportingMultipart .)}}
		{{#with (fileUploadProperties requestBody.defaultContent.schema.properties)}}
		{{#if .}}
		(req, res, next) => {
			const fileFields: multer.Field[] = [{{#each .}}{ name: {{{stringLiteral name}}}{{#if (isNotNull maxCount)}}, maxCount: {{{maxCount}}}{{/if}} }{{#hasMore}}, {{/hasMore}}{{/each}}]
			f.upload.fields(fileFields)(req, res, (error) => {
				if (error?.code === 'LIMIT_UNEXPECTED_FILE') {
					const field = fileFields.find(field => field.name === error.field)
					if (field) {
						res.status(400).type('text/plain; charset=utf-8').send(`The field '${error.field}' allows a maximum of ${field.maxCount} file(s)`)
					} else {
						res.status(400).type('text/plain; charset=utf-8').send(`Unexpected field '${error.field}' in multipart request`)
					}
				} else {
					next(error)
				}
			})
		},
		{{#each .}}
		{{#if minCount}}
		v.verifyMinimumFiles({{{stringLiteral name}}}, {{{minCount}}}),
		{{/if}}
		{{/each}}
		{{/if}}
		{{/with}}
		{{/if}}
		function (req: Request, res: Response) {
			try {
				{{#if securityRequirements}}
				const __user = req.user
				if (!__user) {
					res.status(401)
					res.send()
					return
				}
				{{/if}}
				{{#if requestBody.defaultContent.schema}}
				function __body() {
					const __contentType = req.get('Content-Type')
					const __mimeType = __contentType ? __contentType.replace(/;.*/, '') : undefined

					{{#with requestBody}}
					{{#each contents}}
					if (__mimeType === '{{{mediaType.mimeType}}}') {
						{{#unless schema}}
						return undefined
						{{else}}
						{{#if (isContentMultipart .)}}
						if (req.files && !Array.isArray(req.files)) {
							{{#each (fileUploadProperties schema.properties)}}
							req.body[{{{stringLiteral name}}}] = req.files[{{{stringLiteral name}}}] ? req.files[{{{stringLiteral name}}}]{{#unless isArray}}[0]{{/unless}} : undefined
							{{/each}}
						}
						return {{>frag/fromRequest schema prefix='v.'}}('body', req.body)
						{{else if (isContentJson .)}}
						return {{>frag/fromRequest schema prefix='v.'}}('body', req.body)
						{{else if (isBinary schema)}}
						return req.body as Buffer
						{{else if (isString schema)}}
						return req.body as string
						{{else}}
						return req.body; /* Unsupported mimeType */
						{{/if}}
						{{/unless}}
					}
					{{/each}}
					{{/with}}
					console.error(`Invalid request content type: ${__contentType}`)
					throw new Error(`Invalid request content type: ${__contentType}`)
				}

				{{/if}}
				impl.{{identifier name}}({{!--
				--}}{{#each parameters}}{{>params/query}}{{>params/path}}{{>params/header}}{{>params/form}}{{>params/cookie}}{{#hasMore}}, {{/hasMore}}{{/each}}{{!--
				--}}{{#if requestBody.nativeType}}{{#if parameters}}, {{/if}}{{>params/body}}{{/if}}{{!--
				--}}{{#if securityRequirements}}{{#or parameters requestBody}}, {{/or}}__user{{/if}}{{!--
				--}}).then(function (response) {
					{{#each responses}}
					{{#unless isCatchAll}}
					if (response.status === {{code}}) {
						{{#if defaultContent.schema}}
						let body: any
						try {
							{{#if (isJson defaultContent)}}
							body = {{>frag/toResponse defaultContent.schema prefix='v.'}}('response', response.body)
							{{else}}
							body = response.body
							{{/if}}
						} catch (error) {
							console.error('Invalid response body in {{identifier ../../name}}.{{identifier ../name}}', error)
							res.status(500)
							res.send()
							return
						}

						{{/if}}
						res.status({{code}})
						{{#if headers}}
						{{#each headers}}
						res.header({{{stringLiteral serializedName}}}, `${response.headers[{{{stringLiteral name}}}]}`)
						{{/each}}
						{{/if}}
						{{#if defaultContent}}
						{{#if defaultContent.mediaType.wildcard}}
						res.type(response.mediaType)
						{{else}}
						res.type({{{stringLiteral defaultContent.mediaType.mediaType}}})
						{{/if}}
						{{/if}}
						{{#if defaultContent.schema}}
						res.send(body)
						{{else}}
						res.send()
						{{/if}}
						return
					}
					{{/unless}}
					{{/each}}

					{{#if catchAllResponse}}
					/* Catch-all response */
					{{#with catchAllResponse}}
					{{#if defaultContent.schema}}
					let body: any
					try {
						body = {{>frag/toResponse defaultContent.schema prefix='v.'}}('response', response.body)
					} catch (error) {
						console.error('Invalid response body in {{identifier ../../name}}.{{identifier ../name}}', error)
						res.status(500)
						res.send()
						return
					}

					{{/if}}
					res.status(response.actualStatus)
					{{#if headers}}
					{{#each headers}}
					res.header({{{stringLiteral serializedName}}}, `${response.headers[{{{stringLiteral name}}}]}`)
					{{/each}}
					{{/if}}
					{{#if defaultContent.schema}}
					res.send(body)
					{{else}}
					res.send()
					{{/if}}
					{{/with}}
					{{else}}
					console.log('Unsupported response in {{identifier ../name}}.{{identifier name}}', response)
					res.status(500)
					res.send()
					{{/if}}
				}).catch(function (error) {
					console.error('Unexpected error in {{identifier ../name}}.{{identifier name}}', error.stack || error)
					res.status(500)
					res.send()
				})
			} catch (error) {
				/* Catch validation errors */
				res.status(400)
				res.type('text/plain; charset=utf-8')
				res.send(error)
			}
		}
	)

	{{/each}}
}
