import { getReasonPhrase } from 'http-status-codes';
import * as jwt            from 'jsonwebtoken';
import { JwtPayload }      from 'jsonwebtoken';
import Config              from '../config/Config';
import express             from 'express';
import ApiRequest          from '../types/ApiRequest';
import UserManager         from '../managers/UserManager';
import DojoResponse        from '../shared/types/DojoResponse';
import { User }            from '../types/DatabaseTypes';


class Session {
    private _profile: User;

    get profile(): User {
        return this._profile;
    }

    set profile(newProfile: User) {
        delete newProfile.password;
        this._profile = newProfile;
    }

    constructor() { }

    async initSession(req: ApiRequest) {
        const authorization = req.headers.authorization;
        if ( authorization ) {
            const jwtToken = authorization.replace('Bearer ', '');

            try {
                const jwtData = jwt.verify(jwtToken, Config.jwtConfig.secret) as JwtPayload;

                if ( jwtData.profile ) {
                    this.profile = jwtData.profile;
                    this.profile = await UserManager.getById(this.profile.id);
                }
            } catch ( err ) { }
        }
    }

    private static getToken(profileJson: any): string {
        return profileJson.id === null ? null : jwt.sign({ profile: profileJson }, Config.jwtConfig.secret, Config.jwtConfig.expiresIn > 0 ? { expiresIn: Config.jwtConfig.expiresIn } : {});
    }

    private async getResponse<T>(code: number, data: T, descriptionOverride?: string): Promise<DojoResponse<T>> {
        const profileJson = this.profile;

        let reasonPhrase = '';

        try {
            reasonPhrase = getReasonPhrase(code);
        } catch {}

        return {
            timestamp   : (new Date()).toISOString(),
            code        : code,
            description : descriptionOverride ? descriptionOverride : reasonPhrase,
            sessionToken: Session.getToken(profileJson),
            data        : data
        };
    }

    /*
     Send a response to the client
     Information: Data could be a promise or an object. If it's a promise, we wait on the data to be resolved before sending the response
     */
    sendResponse(res: express.Response, code: number, data?: any, descriptionOverride?: string) {
        Promise.resolve(data).then((toReturn: any) => {
            this.getResponse(code, toReturn, descriptionOverride).then(response => {
                res.status(code).json(response);
            });
        });
    }
}


export default Session;