import {Logger, TaggedLogger, LogLevel} from './types';
import moment from 'moment';
import _ from 'lodash';

export type LoggingFunction = (...args: any[]) => void;

const noopTaggedLogger: TaggedLogger = {
    log(level: LogLevel, ...args: any[]): void {},
    debug(...args: any[]): void {},
    info(...args: any[]): void {},
    warn(...args: any[]): void {},
    error(...args: any[]): void {},
    profile(...args: any[]): void {},
};

export interface ActivatableLogger extends Logger {
    init(enabled: boolean, loggingFunction?: LoggingFunction): void;
}

export class ActivatableLoggerImpl implements ActivatableLogger {
    private enabled: boolean = false;
    private loggingFunction: LoggingFunction = console.info;

    init(enabled: boolean, loggingFunction?: LoggingFunction): void {
        const config = require('./config').config;
        this.enabled = enabled;
        this.loggingFunction = loggingFunction || console.info;
    }

    tag(...tags: string[]): TaggedLogger {
        if (this.enabled) {
            const loggingFunction = this.loggingFunction;
            return {
                log(level: LogLevel, ...args: any[]): void {
                    const timeStr = moment().format('YYYY-MM-DD HH:mm:ss');
                    const levelStr = level.toUpperCase();
                    const tagsStr = tags ? '[' + _.join(tags, ', ') + ']' : '';
                    const messagePrefix = `${timeStr} ${levelStr} - ${tagsStr}`;

                    // Make sure to only replace %s, etc. in real log message
                    // but not in tags.
                    const escapedMessagePrefix = messagePrefix.replace(/%/g, '%%');
                    
                    let message = '';
                    if (args && _.isString(args[0])) {
                        message = args[0];
                        args.shift();
                    }

                    const logStr = message
                        ? `${escapedMessagePrefix} ${message}`
                        : escapedMessagePrefix;
                    loggingFunction(logStr, ...args);
                },
                debug(...args: any[]): void {
                    this.log('debug', ...args);
                },
                info(...args: any[]): void {
                    this.log('info', ...args);
                },
                warn(...args: any[]): void {
                    this.log('warn', ...args);
                },
                error(...args: any[]): void {
                    this.log('error', ...args);
                },
                profile(...args: any[]): void {
                    this.log('profile', ...args);
                },
            }
        } else {
            return noopTaggedLogger;
        }
    }
}

export default new ActivatableLoggerImpl() as ActivatableLogger;