
import { Registry, Counter, Gauge, Histogram, collectDefaultMetrics } from 'prom-client';
import { config } from '../config/index.js';

export class MetricsService {
    private static instance: MetricsService;
    private registry: Registry;

    // --- Metrics Definition ---

    // Operational Events
    public operationalEventsTotal: Counter<string>;

    // Subsystem Metrics
    public subsystemDurationSeconds: Histogram<string>;
    public subsystemLastRunTimestamp: Gauge<string>;
    public subsystemAlive: Gauge<string>;

    // Exchange API Metrics
    public exchangeApiLatencySeconds: Histogram<string>;

    // Risk & Capital Metrics
    public capitalInvariantViolationsTotal: Counter<string>;
    public profileUtilizationPercent: Gauge<string>;

    // Reconciliation Metrics
    public reconciliationMismatchesTotal: Counter<string>;
    public reconciliationMissingItemsCount: Gauge<string>;

    private constructor() {
        this.registry = new Registry();

        // Dynamic labels for every metric
        const env = process.env.NODE_ENV || 'development';
        const mode = config.PAPER_TRADING ? 'paper' : 'live';

        this.registry.setDefaultLabels({
            app: 'bytelyst-trading-bot-service',
            env,
            mode
        });

        collectDefaultMetrics({ register: this.registry });

        // operational_events_total
        this.operationalEventsTotal = new Counter({
            name: 'bytelyst_bot_operational_events_total',
            help: 'Cumulative count of operational events emitted by the system',
            labelNames: ['severity', 'type', 'profile_id', 'symbol'],
            registers: [this.registry]
        });

        // subsystem_duration_seconds
        this.subsystemDurationSeconds = new Histogram({
            name: 'bytelyst_bot_subsystem_duration_seconds',
            help: 'Duration of subsystem loop executions',
            labelNames: ['subsystem'],
            buckets: [0.1, 0.25, 0.5, 1, 2, 5, 10],
            registers: [this.registry]
        });

        // subsystem_last_run_timestamp
        this.subsystemLastRunTimestamp = new Gauge({
            name: 'bytelyst_bot_subsystem_last_run_timestamp',
            help: 'Unix timestamp of the last successful run of a subsystem',
            labelNames: ['subsystem'],
            registers: [this.registry]
        });

        // subsystem_alive
        this.subsystemAlive = new Gauge({
            name: 'bytelyst_bot_subsystem_alive',
            help: 'High-level availability flag for subsystems (1=alive, 0=stalled)',
            labelNames: ['subsystem'],
            registers: [this.registry]
        });

        // exchange_api_latency_seconds
        this.exchangeApiLatencySeconds = new Histogram({
            name: 'bytelyst_bot_exchange_api_latency_seconds',
            help: 'Latency of outgoing exchange API requests',
            labelNames: ['exchange', 'operation'],
            buckets: [0.05, 0.1, 0.25, 0.5, 1, 2, 5],
            registers: [this.registry]
        });

        // capital_invariant_violations_total
        this.capitalInvariantViolationsTotal = new Counter({
            name: 'bytelyst_bot_capital_invariant_violations_total',
            help: 'Cumulative count of capital invariant violations per profile',
            labelNames: ['profile_id'],
            registers: [this.registry]
        });

        // profile_utilization_percent
        this.profileUtilizationPercent = new Gauge({
            name: 'bytelyst_bot_profile_utilization_percent',
            help: 'Percentage of allocated capital currently tied up in positions/orders',
            labelNames: ['profile_id'],
            registers: [this.registry]
        });

        // reconciliation_mismatches_total
        this.reconciliationMismatchesTotal = new Counter({
            name: 'bytelyst_bot_reconciliation_mismatches_total',
            help: 'Cumulative count of detected state mismatches between DB and Exchange',
            registers: [this.registry]
        });

        // reconciliation_missing_items_count
        this.reconciliationMissingItemsCount = new Gauge({
            name: 'bytelyst_bot_reconciliation_missing_items_count',
            help: 'Count of missing items detected in the last reconciliation cycle',
            labelNames: ['source'],
            registers: [this.registry]
        });
    }

    public static getInstance(): MetricsService {
        if (!MetricsService.instance) {
            MetricsService.instance = new MetricsService();
        }
        return MetricsService.instance;
    }

    public async getMetrics(): Promise<string> {
        return await this.registry.metrics();
    }

    public getContentType(): string {
        return this.registry.contentType;
    }
}

export const metrics = MetricsService.getInstance();
