import api from './api';

interface ErrorLog {
    message: string;
    stack?: string;
    componentStack?: string;
    url: string;
    userAgent: string;
    timestamp: string;
    userId?: string;
    extra?: Record<string, unknown>;
}

interface PerformanceMetric {
    name: string;
    value: number;
    unit: 'ms' | 'bytes' | 'count';
    url: string;
    timestamp: string;
}

class MonitoringService {
    private errorQueue: ErrorLog[] = [];
    private metricsQueue: PerformanceMetric[] = [];
    private flushInterval: number | null = null;
    private isEnabled: boolean;

    constructor() {
        // Only enable in production or if explicitly enabled
        this.isEnabled = import.meta.env.PROD || import.meta.env.VITE_ENABLE_MONITORING === 'true';

        if (this.isEnabled) {
            this.startFlushing();
            this.setupGlobalHandlers();
        }
    }

    private startFlushing() {
        // Flush logs every 30 seconds
        this.flushInterval = window.setInterval(() => {
            this.flush();
        }, 30000);

        // Also flush on page unload
        window.addEventListener('beforeunload', () => this.flush());
    }

    private setupGlobalHandlers() {
        // Catch unhandled errors
        window.addEventListener('error', (event) => {
            this.logError(event.error || new Error(event.message), {
                filename: event.filename,
                lineno: event.lineno,
                colno: event.colno
            });
        });

        // Catch unhandled promise rejections
        window.addEventListener('unhandledrejection', (event) => {
            const error = event.reason instanceof Error
                ? event.reason
                : new Error(String(event.reason));
            this.logError(error, { type: 'unhandledrejection' });
        });
    }

    logError(error: Error, extra?: Record<string, unknown>) {
        if (!this.isEnabled) {
            console.error('[Monitoring] Error:', error, extra);
            return;
        }

        const errorLog: ErrorLog = {
            message: error.message,
            stack: error.stack,
            url: window.location.href,
            userAgent: navigator.userAgent,
            timestamp: new Date().toISOString(),
            userId: this.getUserId(),
            extra
        };

        this.errorQueue.push(errorLog);

        // Immediately flush if queue is large
        if (this.errorQueue.length >= 10) {
            this.flush();
        }
    }

    logComponentError(error: Error, componentStack: string) {
        if (!this.isEnabled) {
            console.error('[Monitoring] Component Error:', error, componentStack);
            return;
        }

        const errorLog: ErrorLog = {
            message: error.message,
            stack: error.stack,
            componentStack,
            url: window.location.href,
            userAgent: navigator.userAgent,
            timestamp: new Date().toISOString(),
            userId: this.getUserId()
        };

        this.errorQueue.push(errorLog);
        this.flush(); // Immediately flush component errors
    }

    logMetric(name: string, value: number, unit: 'ms' | 'bytes' | 'count' = 'ms') {
        if (!this.isEnabled) return;

        this.metricsQueue.push({
            name,
            value,
            unit,
            url: window.location.href,
            timestamp: new Date().toISOString()
        });
    }

    // Track page load performance
    trackPageLoad() {
        if (!this.isEnabled || typeof window.performance === 'undefined') return;

        // Wait for load to complete
        window.addEventListener('load', () => {
            setTimeout(() => {
                const timing = performance.timing;
                const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;

                if (navigation) {
                    this.logMetric('page_load', navigation.loadEventEnd - navigation.startTime);
                    this.logMetric('dom_content_loaded', navigation.domContentLoadedEventEnd - navigation.startTime);
                    this.logMetric('first_byte', navigation.responseStart - navigation.requestStart);
                } else if (timing) {
                    this.logMetric('page_load', timing.loadEventEnd - timing.navigationStart);
                    this.logMetric('dom_content_loaded', timing.domContentLoadedEventEnd - timing.navigationStart);
                }

                // Track Core Web Vitals if available
                this.trackWebVitals();
            }, 0);
        });
    }

    private trackWebVitals() {
        // Largest Contentful Paint
        const lcpObserver = new PerformanceObserver((list) => {
            const entries = list.getEntries();
            const lastEntry = entries[entries.length - 1];
            this.logMetric('lcp', lastEntry.startTime);
        });
        try {
            lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });
        } catch (e) {
            // Not supported
        }

        // First Input Delay
        const fidObserver = new PerformanceObserver((list) => {
            const entries = list.getEntries();
            entries.forEach((entry: any) => {
                this.logMetric('fid', entry.processingStart - entry.startTime);
            });
        });
        try {
            fidObserver.observe({ type: 'first-input', buffered: true });
        } catch (e) {
            // Not supported
        }

        // Cumulative Layout Shift
        let clsValue = 0;
        const clsObserver = new PerformanceObserver((list) => {
            list.getEntries().forEach((entry: any) => {
                if (!entry.hadRecentInput) {
                    clsValue += entry.value;
                }
            });
        });
        try {
            clsObserver.observe({ type: 'layout-shift', buffered: true });
            // Report CLS on page hide
            window.addEventListener('visibilitychange', () => {
                if (document.visibilityState === 'hidden') {
                    this.logMetric('cls', clsValue, 'count');
                }
            });
        } catch (e) {
            // Not supported
        }
    }

    private getUserId(): string | undefined {
        try {
            const user = localStorage.getItem('user');
            if (user) {
                return JSON.parse(user).id;
            }
        } catch {
            // Ignore
        }
        return undefined;
    }

    private async flush() {
        if (this.errorQueue.length === 0 && this.metricsQueue.length === 0) return;

        const errors = [...this.errorQueue];
        const metrics = [...this.metricsQueue];

        this.errorQueue = [];
        this.metricsQueue = [];

        try {
            if (errors.length > 0) {
                await api.post('/monitoring/errors', { errors }).catch(() => {
                    // Silently fail - don't want monitoring to break the app
                    console.debug('[Monitoring] Failed to send error logs');
                });
            }

            if (metrics.length > 0) {
                await api.post('/monitoring/metrics', { metrics }).catch(() => {
                    console.debug('[Monitoring] Failed to send metrics');
                });
            }
        } catch {
            // Silently fail
        }
    }

    destroy() {
        if (this.flushInterval) {
            clearInterval(this.flushInterval);
        }
    }
}

// Singleton instance
export const monitoring = new MonitoringService();

// Start tracking on import
monitoring.trackPageLoad();
