import Models, { sequelize } from "../models";
import { AppError } from "../../utils/errors";
import _ from 'lodash';
import Hapi, { Request } from '@hapi/hapi'
import { Common } from "../../utils/common"
import AppCache from "../../utils/appCache";

export class SessionDao {
    static initiateSession = async (server: Hapi.Server) => {
        try {
            let offset = 0;
            let hasMore = true;
            while (hasMore) {
                const sessions = await Models.Session.findAll({
                    attributes: ['token', 'accountId', 'userId'],
                    limit: +process.env.BATCH_SIZE!,
                    offset,
                    raw: true,
                });

                if (sessions.length === 0) {
                    hasMore = false;
                    break;
                }
                for (const session of sessions) {
                    let key = 'session_' + (session.accountId ? +session.accountId + '_' : '') + session.userId;
                    let existingSession = AppCache.get(key) as unknown as Text[];
                    if (existingSession) {
                        existingSession.push(session.token)
                        AppCache.set(key, existingSession);
                    } else {
                        AppCache.set(key, [session.token]);
                    }
                }
                offset += +process.env.BATCH_SIZE!;
            }
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_WITH_DAO', err);
        }
    }

    static set = async (request: Request, accountId: number | null, userId: number, token: Text) => {
        try {
            let key = 'session_' + (accountId ? +accountId + '_' : '') + userId;
            let existingSession = AppCache.get(key) as unknown as Text[];
            if (existingSession) {
                existingSession.push(token)
                AppCache.set(key, existingSession);
                await Common.EmitEvent(null, 'updateCache', { index: key, value: existingSession})
            } else {
                AppCache.set(key, [token]);
                await Common.EmitEvent(null, 'updateCache', { index: key, value: [token]})
            }
            await Models.Session.create({ userId: userId, accountId: accountId, token: token });
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_WITH_DAO', err);
        }
    }

    static verify = async (request: Request, accountId: number | null, userId: number, token: Text) => {
        try {
            let key = 'session_' + (accountId ? +accountId + '_' : '') + userId;
            let existingSession = AppCache.get(key) as unknown as Text[];
            if (existingSession && existingSession.includes(token)) {
                return true
            }
            return false;
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_WITH_DAO', err);
        }
    }

    static remove = async (request: Request, accountId: number | null, userId: number, token: Text | null, removeall: boolean) => {
        try {
            let key = 'session_' + (accountId ? +accountId + '_' : '') + userId;
            let existingSession = AppCache.get(key) as unknown as Text[];
            if (removeall) {
                await Models.Session.destroy({ where: { userId: userId, accountId: accountId }, force: true });
                AppCache.del(key);
                await Common.EmitEvent(null, 'updateCache', { index: key, value: null})
            } else {
                await Models.Session.destroy({ where: { userId: userId, accountId: accountId, token: token }, force: true });
                const updatedSession = existingSession.filter((session: Text) => session !== token);
                AppCache.set(key, updatedSession);
                await Common.EmitEvent(null, 'updateCache', { index: key, value: updatedSession})
            }
            return false;
        } catch (err) {
            if (err instanceof AppError) { throw err; }
            throw new AppError(500, 'SOMETHING_WENT_WRONG_WITH_DAO', err);
        }
    }
}