import * as fs from 'fs';
import * as yaml from 'js-yaml';
// This config is good if you're running the otel-lgtm stack locally
const DEFAULT_CONFIG = {
    grafanaEndpoint: 'http://localhost:3000/api/datasources/proxy/uid/prometheus/api/v1',
    grafanaCredentials: 'admin:admin'
};
export class AlertChecker {
    config;
    logger;
    constructor(logger, config = {}){
        this.config = {
            ...DEFAULT_CONFIG,
            ...config
        };
        this.logger = logger;
    }
    /**
   * Load the alerts config from a file path.
   * @param filePath - The absolute path to the alerts file.
   */ loadAlertsConfig(filePath) {
        const fileContents = fs.readFileSync(filePath, 'utf8');
        const data = yaml.load(fileContents);
        return data.alerts;
    }
    async queryGrafana({ expr, start, end, step }) {
        const credentials = Buffer.from(this.config.grafanaCredentials).toString('base64');
        let query = `query=${encodeURIComponent(expr)}`;
        let action = 'query';
        if (start) {
            action = 'query_range';
            query += `&start=${start}`;
        }
        if (end) {
            query += `&end=${end}`;
        }
        if (step) {
            query += `&step=${step}`;
        }
        const urlString = `${this.config.grafanaEndpoint}/${action}?${query}`;
        this.logger.debug(`Querying Grafana: ${urlString}`);
        const response = await fetch(urlString, {
            headers: {
                Authorization: `Basic ${credentials}`
            }
        });
        if (!response.ok) {
            throw new Error(`Failed to fetch data from Grafana: ${response.statusText}`);
        }
        const data = await response.json();
        const result = data.data.result;
        return result.length > 0 ? parseFloat(result[0].value[1]) : 0;
    }
    async checkAlerts(alerts) {
        let alertTriggered = false;
        for (const alert of alerts){
            this.logger.info(`Checking alert: ${JSON.stringify(alert)}`);
            const metricValue = await this.queryGrafana(alert);
            this.logger.info(`Metric value: ${metricValue}`);
            if (metricValue > 0) {
                this.logger.error(`Alert ${alert.alert} triggered! Value: ${metricValue}`);
                alertTriggered = true;
            } else {
                this.logger.info(`Alert ${alert.alert} passed.`);
            }
        }
        if (alertTriggered) {
            throw new AlertTriggeredError('Test failed due to triggered alert');
        }
    }
    /**
   * Run the alert check based on the alerts defined in an array.
   * @param alerts - The alerts to check.
   */ async runAlertCheck(alerts) {
        try {
            await this.checkAlerts(alerts);
            this.logger.info('All alerts passed.');
        } catch (error) {
            this.logger.error(error instanceof Error ? error.message : String(error));
            throw error;
        }
    }
    /**
   * Run the alert check based on the alerts defined in a yaml file.
   * @param filePath - The absolute path to the alerts file.
   */ async runAlertCheckFromFilePath(filePath) {
        const alerts = this.loadAlertsConfig(filePath);
        await this.checkAlerts(alerts);
    }
}
export class AlertTriggeredError extends Error {
    name = 'AlertTriggeredError';
}
