"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ApiTransport = void 0;
const axios_1 = __importDefault(require("axios"));
const fs_1 = require("fs");
const path_1 = __importDefault(require("path"));
const winston_transport_1 = __importDefault(require("winston-transport"));
const logManagementService_1 = require("../services/logManagementService");
class ApiTransport extends winston_transport_1.default {
    constructor(options) {
        super(options);
        this.logBuffer = [];
        this.flushTimer = null;
        this.isFlushing = false;
        this.retryCount = 0;
        this.failedLogs = [];
        this.logManagementService = null;
        this.options = options;
        this.logFilePath = path_1.default.join(process.cwd(), 'logs', 'private-logs.json');
        // Ensure logs directory exists
        this.ensureLogDirectory();
        // Initialize log management service if enabled
        this.initializeLogManagement();
        // Start the flush timer
        this.startFlushTimer();
    }
    async ensureLogDirectory() {
        try {
            await fs_1.promises.mkdir(path_1.default.dirname(this.logFilePath), { recursive: true });
        }
        catch (error) {
            console.error('Failed to create logs directory:', error);
        }
    }
    initializeLogManagement() {
        if (this.options.logManagement?.enabled) {
            const config = {
                logsDirectory: path_1.default.dirname(this.logFilePath),
                retentionDays: this.options.logManagement.retentionDays,
                emailConfig: this.options.emailConfig,
                dumpIntervalHours: this.options.logManagement.dumpIntervalHours,
                purgeIntervalHours: this.options.logManagement.purgeIntervalHours,
            };
            this.logManagementService = new logManagementService_1.LogManagementService(config);
            console.log('📊 Log management service initialized with retention:', config.retentionDays, 'days');
            // Perform initial log management operations
            this.performAutomaticLogManagement().catch((error) => {
                console.error('Initial log management failed:', error);
            });
        }
    }
    async sendEmail(options) {
        if (!this.options.emailConfig.url) {
            throw new Error('Email URL not configured');
        }
        const response = await axios_1.default.post(this.options.emailConfig.url, options);
        if (response.status !== 200) {
            throw new Error(`Failed to send email: ${response.status}`);
        }
    }
    startFlushTimer() {
        if (this.flushTimer) {
            clearInterval(this.flushTimer);
        }
        this.flushTimer = setInterval(() => {
            this.flushLogs();
        }, this.options.flushInterval);
    }
    log(info, callback) {
        console.log('📝 ApiTransport received log:', info);
        // Add to buffer
        this.logBuffer.push({
            ...info,
            timestamp: new Date().toISOString(),
        });
        console.log(`📦 Buffer size: ${this.logBuffer.length}/${this.options.batchSize}`);
        // Check if we need to flush based on batch size
        if (this.logBuffer.length >= this.options.batchSize) {
            console.log('🚀 Flushing logs due to batch size reached');
            this.flushLogs();
        }
        // Emit the logged event
        setImmediate(() => {
            this.emit('logged', info);
        });
        callback();
    }
    async flushLogs() {
        if (this.isFlushing || this.logBuffer.length === 0) {
            // console.log(`⏭️ Skipping flush - isFlushing: ${this.isFlushing}, bufferSize: ${this.logBuffer.length}`);
            return;
        }
        console.log(`🔄 Starting flush with ${this.logBuffer.length} logs`);
        this.isFlushing = true;
        const logsToSend = [...this.logBuffer];
        this.logBuffer = [];
        try {
            await this.sendLogsToApi(logsToSend);
            console.log('✅ Successfully sent logs to API');
            this.retryCount = 0; // Reset retry count on success
        }
        catch (error) {
            console.error('❌ Failed to send logs to API:', error);
            await this.handleApiFailure(logsToSend, error);
        }
        finally {
            this.isFlushing = false;
        }
    }
    async sendLogsToApi(logs) {
        if (!this.options.apiUrl) {
            throw new Error('API URL not configured');
        }
        try {
            const response = await axios_1.default.post(this.options.apiUrl, {
                logs,
                timestamp: new Date().toISOString(),
                source: 'auto-flush-interval',
            }, {
                headers: {
                    'Content-Type': 'application/json',
                },
            });
            if ([201, 200].includes(response.status) === false) {
                throw new Error(`API request failed with status: ${response.status}`);
            }
            console.log(`✅ Successfully sent ${logs.length} logs to API`);
        }
        catch (error) {
            if (error.response) {
                // Server responded with error status
                throw new Error(`API request failed: ${error.response.status} - ${error.response.data}`);
            }
            else if (error.request) {
                // Request was made but no response received
                throw new Error(`API request failed: No response received - ${error.message}`);
            }
            else {
                // Something else happened
                throw new Error(`API request failed: ${error.message}`);
            }
        }
    }
    async handleApiFailure(logs, error) {
        this.retryCount++;
        if (this.retryCount <= this.options.maxRetries) {
            // Retry with exponential backoff
            const delay = Math.min(1000 * Math.pow(2, this.retryCount - 1), 30000);
            console.log(`Retrying API call in ${delay}ms (attempt ${this.retryCount}/${this.options.maxRetries})`);
            setTimeout(async () => {
                this.logBuffer.unshift(...logs); // Add logs back to buffer for retry
                await this.flushLogs();
            }, delay);
        }
        else {
            // Max retries exceeded, save to file and send email
            console.error(`Max retries (${this.options.maxRetries}) exceeded. Saving logs to file and sending email.`);
            this.failedLogs.push(...logs);
            await this.saveLogsToFile(logs);
            await this.sendFailureEmail(error, logs);
            // Trigger log dump if log management is enabled
            if (this.logManagementService) {
                try {
                    await this.logManagementService.performLogDump();
                    console.log('📊 Log dump triggered due to API failure');
                }
                catch (dumpError) {
                    console.error('Failed to trigger log dump:', dumpError);
                }
            }
            // Reset retry count for future batches
            this.retryCount = 0;
        }
    }
    async saveLogsToFile(logs) {
        try {
            const logEntry = {
                timestamp: new Date().toISOString(),
                logs,
                error: 'API failure - logs saved to file',
            };
            await fs_1.promises.appendFile(this.logFilePath, JSON.stringify(logEntry) + '\n');
        }
        catch (error) {
            console.error('Failed to save logs to file:', error);
        }
    }
    async sendFailureEmail(error, logs) {
        try {
            const subject = `Private Logger API Failure - ${new Date().toISOString()}`;
            const body = `
Billing Logger API has failed after ${this.options.maxRetries} retries.

Error: ${error.message || error}

Number of failed logs: ${logs.length}
Log file location: ${this.logFilePath}

Recent logs (first 10):
${JSON.stringify(logs.slice(0, 10), null, 2)}

Please check the API endpoint and configuration.
      `;
            await this.sendEmail({
                to: this.options.emailConfig.toEmail,
                from: this.options.emailConfig.fromEmail,
                subject,
                text: body,
                html: body.replace(/\n/g, '<br>'),
            });
        }
        catch (emailError) {
            console.error('Failed to send failure email:', emailError);
        }
    }
    // Public method to manually trigger flush (useful for testing)
    async forceFlush() {
        console.log('🔄 Force flushing logs...');
        await this.flushLogs();
    }
    // Get current buffer status
    getBufferStatus() {
        return {
            length: this.logBuffer.length,
            batchSize: this.options.batchSize,
            isFlushing: this.isFlushing,
        };
    }
    // Internal method for automatic log management (no manual triggers)
    async performAutomaticLogManagement() {
        if (this.logManagementService) {
            try {
                // Automatically perform log dump and purge
                await this.logManagementService.performLogDump();
                await this.logManagementService.performLogPurge();
            }
            catch (error) {
                console.error('Automatic log management failed:', error);
            }
        }
    }
    close() {
        if (this.flushTimer) {
            clearInterval(this.flushTimer);
        }
        // Stop log management service
        if (this.logManagementService) {
            this.logManagementService.stop();
        }
        // Flush any remaining logs before closing
        if (this.logBuffer.length > 0) {
            this.flushLogs().catch((error) => {
                console.error('Error flushing logs on close:', error);
            });
        }
    }
}
exports.ApiTransport = ApiTransport;
//# sourceMappingURL=apiTransport.js.map