import {
    AuthRequiredMiddleware,
    BasicLoginAttempt,
    BasicLoginAttemptType,
    BasicRegistrationAttempt,
    BasicRegistrationAttemptType,
    GuestRequiredMiddleware,
    Request,
    right,
    Route,
    SessionAuthMiddleware,
    Validator,
} from '@extollo/lib'
import {Dash} from '../controllers/Dash.controller'
import CobaltMiddleware from '../middlewares/Cobalt.middleware'
import {ResourceAPI} from '../controllers/cobalt/ResourceAPI.controller'
import {Interface} from '../controllers/cobalt/Interface.controller'
import {Registration} from '../controllers/auth/Registration.controller'
import {Login} from '../controllers/auth/Login.controller'

const parseKey = (request: Request) => right(request.safe('key').string())
const parseId = (request: Request) => {
    request.safe('id').present()
    return right(request.input('id') as number|string)
}

Route
    .group('/dash', () => {
        Route.get('/')
            .alias('@dash')
            .calls<Dash>(Dash, dash => dash.main)

        Route.get('/provision')
            .calls<Dash>(Dash, dash => dash.provision)

        Route.group('/cobalt/resource', () => {
            Route.get('/:key/configure')
                .parameterMiddleware(parseKey)
                .calls(ResourceAPI, (api: ResourceAPI) => api.configure)

            Route.get('/:key')
                .parameterMiddleware(parseKey)
                .calls(ResourceAPI, (api: ResourceAPI) => api.read)

            Route.get('/:key/:id')
                .parameterMiddleware(parseKey)
                .parameterMiddleware(parseId)
                .calls(ResourceAPI, (api: ResourceAPI) => api.readOne)

            Route.put('/:key')
                .parameterMiddleware(parseKey)
                .passingRequest()
                .calls(ResourceAPI, (api: ResourceAPI) => api.create)

            Route.patch('/:key/:id')
                .parameterMiddleware(parseKey)
                .parameterMiddleware(parseId)
                .passingRequest()
                .calls(ResourceAPI, (api: ResourceAPI) => api.update)

            Route.delete('/:key/:id')
                .parameterMiddleware(parseKey)
                .parameterMiddleware(parseId)
                .calls(ResourceAPI, (api: ResourceAPI) => api.delete)
        })

        Route.get('/cobalt/listing/:key')
            .parameterMiddleware(parseKey)
            .calls(Interface, (i: Interface) => i.listing)

        Route.get('/cobalt/form/:key')
            .parameterMiddleware(parseKey)
            .calls(Interface, (i: Interface) => i.insertForm)

        Route.get('/cobalt/form/:key/:id')
            .parameterMiddleware(parseKey)
            .parameterMiddleware(parseId)
            .calls(Interface, (i: Interface) => i.updateForm)

        Route.get('/cobalt/form/:key/:id/view')
            .parameterMiddleware(parseKey)
            .parameterMiddleware(parseId)
            .calls(Interface, (i: Interface) => i.viewForm)
    })
    .pre(SessionAuthMiddleware)
    .pre(AuthRequiredMiddleware)
    .pre(CobaltMiddleware)

Route.group('/iam', () => {
    Route.get('/register')
        .pre(GuestRequiredMiddleware)
        .pre(SessionAuthMiddleware)
        .calls<Registration>(Registration, reg => reg.registration)

    Route.post('/register')
        .pre(GuestRequiredMiddleware)
        .pre(SessionAuthMiddleware)
        .input(Validator.fromSchema<BasicRegistrationAttempt>(BasicRegistrationAttemptType))
        .calls<Registration>(Registration, reg => reg.register)

    Route.get('/login')
        .pre(GuestRequiredMiddleware)
        .pre(SessionAuthMiddleware)
        .alias('@auth:login')
        .calls<Login>(Login, login => login.login)

    Route.post('/login')
        .pre(GuestRequiredMiddleware)
        .pre(SessionAuthMiddleware)
        .input(Validator.fromSchema<BasicLoginAttempt>(BasicLoginAttemptType))
        .calls<Login>(Login, login => login.attemptLogin)

    Route.any('/logout')
        .pre(AuthRequiredMiddleware)
        .pre(SessionAuthMiddleware)
        .alias('@auth:logout')
        .calls<Login>(Login, login => login.logout)
})
