import winston from "winston";
import nodemailer from "nodemailer";
import TransportStream from "winston-transport";
import Mail from "nodemailer/lib/mailer";
import { isHttpError, hasStackTrace } from "./util";
import { inspect } from "util";

export const logger = winston.createLogger({
    level: "debug",
    transports: [
        new winston.transports.Console({
            handleExceptions: true,
            level: "debug",
            debugStdout: true,
            format: winston.format.combine(
                winston.format.splat(),
                winston.format.prettyPrint(),
                winston.format.cli()
            ),
        }),
    ]
});

process.on("unhandledRejection", (reason) => {
    
    if (isHttpError(reason))
        throw new Error(`HTTPError: ${reason.request.requestUrl} failed because ${reason}\nStack trace: ${reason.stack}`);
    if (hasStackTrace(reason))
        throw new Error(`Unhandled rejection: ${reason}\nFull stack trace: ${reason.stack}`);
    let contents = `${reason}`;
    try {
        contents = inspect(reason, true, null);
    } catch (e) { 
        // ignored
    }
    throw new Error(`Unhandled rejection: ${contents}`); 
});

interface LogMessage {
    message: string;       
}

class EmailTransport extends TransportStream {
    private mailer: Mail;

    constructor(opts?: TransportStream.TransportStreamOptions) {
        super(opts);
        console.log(`Username: ${process.env.GMAIL_NAME}`);
        this.mailer = nodemailer.createTransport({
            host: "smtp.gmail.com",
            port: 465,
            secure: true,
            auth: {
                user: process.env.GMAIL_NAME,
                pass: process.env.GMAIL_PASSWORD
            }
        });
    }

    log(info: LogMessage, next: () => void): void {
        setImmediate(() => {
            this.emit("logged", info);
        });

        this.mailer.sendMail({
            from: `${process.env.GMAIL_NAME}@gmail.com`,
            to: process.env.ERRORS_ADDR,
            subject: `Error at ${new Date().toISOString()}`,
            text: `Received error data: ${info.message}`
        }).catch(err => console.log(`Failed to send email! ${err}`));

        next();
    }
}

if (process.env.NODE_ENV == "production") {
    logger.add(new EmailTransport({
        level: "error",
        handleExceptions: true,
        format: winston.format.combine(
            winston.format.splat(),
            winston.format.simple()
        )
    }));
}