'use strict';

const os    = require('os');
const fs    = require('fs');
const https = require('https');
const qs    = require('querystring');

const CREDS_PATH = 'C:\\ProgramData\\dataforth-uploader\\credentials.json';
const TO         = ['mike@azcomputerguru.com'];  // add jlehman@dataforth.com once confirmed working
const FROM       = 'sysadmin@dataforth.com';
const HOST       = os.hostname();
const PREFIX     = '[NOTIFY]';
const SEP_EQ     = '='.repeat(60);
const SEP_DAS    = '-'.repeat(60);

function loadGraphCreds() {
    try {
        const raw = fs.readFileSync(CREDS_PATH, 'utf8');
        const c   = JSON.parse(raw);
        if (!c.GRAPH_TENANT_ID || !c.GRAPH_CLIENT_ID || !c.GRAPH_CLIENT_SECRET) {
            process.stderr.write(`${PREFIX} GRAPH_TENANT_ID/CLIENT_ID/CLIENT_SECRET not in credentials.json — skipping email\n`);
            return null;
        }
        return { tenantId: c.GRAPH_TENANT_ID, clientId: c.GRAPH_CLIENT_ID, clientSecret: c.GRAPH_CLIENT_SECRET };
    } catch (e) {
        process.stderr.write(`${PREFIX} Could not load credentials.json: ${e.message} — skipping email\n`);
        return null;
    }
}

function httpsPost(hostname, path, headers, body) {
    return new Promise((resolve, reject) => {
        const data = Buffer.from(body);
        const req  = https.request({ hostname, path, method: 'POST', headers: { ...headers, 'Content-Length': data.length } }, (res) => {
            const chunks = [];
            res.on('data', (c) => chunks.push(c));
            res.on('end', () => resolve({ status: res.statusCode, body: Buffer.concat(chunks).toString('utf8') }));
        });
        req.on('error', reject);
        req.write(data);
        req.end();
    });
}

async function getToken(creds) {
    const body = qs.stringify({
        grant_type:    'client_credentials',
        client_id:     creds.clientId,
        client_secret: creds.clientSecret,
        scope:         'https://graph.microsoft.com/.default',
    });
    const res = await httpsPost(
        'login.microsoftonline.com',
        `/${creds.tenantId}/oauth2/v2.0/token`,
        { 'Content-Type': 'application/x-www-form-urlencoded' },
        body
    );
    const parsed = JSON.parse(res.body);
    if (!parsed.access_token) throw new Error(`Token error: ${parsed.error} — ${parsed.error_description}`);
    return parsed.access_token;
}

async function sendMail(subject, text) {
    const creds = loadGraphCreds();
    if (!creds) return;

    try {
        const token = await getToken(creds);
        const payload = JSON.stringify({
            message: {
                subject,
                body:         { contentType: 'Text', content: text },
                toRecipients: TO.map((a) => ({ emailAddress: { address: a } })),
                from:         { emailAddress: { address: FROM } },
            },
        });
        const res = await httpsPost(
            'graph.microsoft.com',
            `/v1.0/users/${FROM}/sendMail`,
            { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
            payload
        );
        if (res.status !== 202) {
            process.stderr.write(`${PREFIX} sendMail HTTP ${res.status}: ${res.body.slice(0, 200)}\n`);
        }
    } catch (e) {
        process.stderr.write(`${PREFIX} sendMail failed: ${e.message}\n`);
    }
}

function buildAlertText(subject, context) {
    const lines = [];
    const ts = new Date().toISOString();

    lines.push(`Host:    ${HOST}`);
    lines.push(`Time:    ${ts}`);
    lines.push(`Subject: [TestDataDB] ALERT: ${subject}`);
    lines.push(SEP_DAS);

    if (context.stage !== undefined) lines.push(`Stage:   ${context.stage}`);

    if (context.error !== undefined) {
        lines.push('');
        lines.push(`Error: ${context.error}`);
    }

    if (Array.isArray(context.details) && context.details.length > 0) {
        lines.push('');
        for (const line of context.details) lines.push(`  ${line}`);
    }

    if (context.stats !== undefined) {
        lines.push('');
        lines.push(`Stats: ${JSON.stringify(context.stats, null, 2)}`);
    }

    return lines.join('\n');
}

/**
 * Send an alert email for pipeline errors.
 * Never throws — callers do not guard this.
 *
 * @param {string} subject - Short description; prefixed with [TestDataDB] ALERT:
 * @param {object} [context={}]
 * @param {string}   [context.stage]   - Pipeline stage where the alert fired
 * @param {string}   [context.error]   - Error message
 * @param {string[]} [context.details] - Additional detail lines
 * @param {object}   [context.stats]   - Stats object
 */
function alert(subject, context) {
    context = context || {};

    try {
        const preview = [
            `${PREFIX} ${SEP_EQ}`,
            `${PREFIX} ALERT: [TestDataDB] ${subject}`,
            `${PREFIX} Host: ${HOST} | Time: ${new Date().toISOString()}`,
        ];
        if (context.stage)   preview.push(`${PREFIX} Stage: ${context.stage}`);
        if (context.error)   preview.push(`${PREFIX} Error: ${context.error}`);
        if (context.details) for (const d of context.details) preview.push(`${PREFIX}   ${d}`);
        if (context.stats)   preview.push(`${PREFIX} Stats: ${JSON.stringify(context.stats)}`);
        preview.push(`${PREFIX} ${SEP_EQ}`);
        for (const line of preview) process.stderr.write(line + '\n');
    } catch (_) {}

    const text = buildAlertText(subject, context);
    sendMail(`[TestDataDB] ALERT: ${subject}`, text).catch(() => {});
}

/**
 * Send a daily pipeline summary email.
 *
 * @param {object} stats
 * @param {number} stats.received
 * @param {number} stats.created
 * @param {number} stats.updated
 * @param {number} stats.unchanged
 * @param {number} stats.errors
 * @returns {Promise<void>}
 */
async function summary(stats) {
    const date    = new Date().toISOString().slice(0, 10);
    const status  = (stats.errors > 0) ? 'FAIL' : 'OK';
    const subject = `[TestDataDB] Daily pipeline ${status} — ${date}`;

    const lines = [
        `Host:      ${HOST}`,
        `Time:      ${new Date().toISOString()}`,
        `Date:      ${date}`,
        `Status:    ${status}`,
        SEP_DAS,
        `Received:  ${stats.received}`,
        `Created:   ${stats.created}`,
        `Updated:   ${stats.updated}`,
        `Unchanged: ${stats.unchanged}`,
        `Errors:    ${stats.errors}`,
    ];

    process.stderr.write(`${PREFIX} Sending daily summary (${status}) for ${date}\n`);
    await sendMail(subject, lines.join('\n'));
}

if (require.main === module) {
    const cmd = process.argv[2];
    if (cmd === 'summary') {
        let stats;
        try {
            stats = JSON.parse(process.argv[3] || '{}');
        } catch (e) {
            process.stderr.write(`${PREFIX} Could not parse stats JSON: ${e.message}\n`);
            process.exit(1);
        }
        summary(stats).then(() => process.exit(0)).catch((e) => {
            process.stderr.write(`${PREFIX} summary failed: ${e.message}\n`);
            process.exit(1);
        });
    } else {
        process.stderr.write(`${PREFIX} Unknown command: ${cmd}\n`);
        process.exit(1);
    }
}

module.exports = { alert, summary };
