const db = require('./analytics-db');
const { parseUserAgent } = require('./user-agent-parser');

/**
 * Analytics Collector Module - SQLite Edition
 * Handles tracking, storage, and retrieval of game analytics data
 */
class AnalyticsCollector {
    constructor() {
        // Prepare statements for better performance
        this.statements = {
            insertVisitor: db.prepare(`
                INSERT OR REPLACE INTO visitors (user_id, first_seen, last_seen)
                VALUES (?, COALESCE((SELECT first_seen FROM visitors WHERE user_id = ?), ?), ?)
            `),
            insertPageView: db.prepare(`
                INSERT INTO page_views (user_id, game_name, timestamp, date, hour, device_type, os, browser)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?)
            `),
            insertSession: db.prepare(`
                INSERT OR IGNORE INTO sessions (session_id, user_id, game_name, start_time, device_type, os, browser, match_id)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?)
            `),
            updateSession: db.prepare(`
                UPDATE sessions 
                SET end_time = ?, duration = ?, metrics = ?
                WHERE session_id = ?
            `)
        };
    }

    /**
     * Generate unique user ID from IP and User-Agent
     */
    generateUserId(ip, userAgent) {
        const crypto = require('crypto');
        const hash = crypto.createHash('sha256');
        hash.update(`${ip}-${userAgent}`);
        return hash.digest('hex').substring(0, 16);
    }

    /**
     * Track a page view event
     */
    async trackPageView(userId, gameName = 'portal', userAgent = null) {
        const now = new Date().toISOString();
        const date = now.split('T')[0];
        const hour = new Date().getHours();
        const { deviceType, os, browser } = parseUserAgent(userAgent);

        try {
            db.transaction(() => {
                this.statements.insertVisitor.run(userId, userId, now, now);
                this.statements.insertPageView.run(userId, gameName, now, date, hour, deviceType, os, browser);
            })();
        } catch (error) {
            console.error('Error tracking page view:', error);
        }
    }

    /**
     * Track game start event
     */
    async trackGameStart(userId, gameName, sessionId, userAgent = null, matchId = null) {
        const now = new Date().toISOString();
        const { deviceType, os, browser } = parseUserAgent(userAgent);

        try {
            this.statements.insertSession.run(sessionId, userId, gameName, now, deviceType, os, browser, matchId);
        } catch (error) {
            console.error('Error tracking game start:', error);
        }
    }

    /**
     * Track game end event
     */
    async trackGameEnd(sessionId, duration, metrics = null) {
        const now = new Date().toISOString();
        
        // Stringify metrics if it's an object
        const metricsJson = metrics && typeof metrics === 'object' ? JSON.stringify(metrics) : metrics;

        try {
            this.statements.updateSession.run(now, duration, metricsJson, sessionId);
        } catch (error) {
            console.error('Error tracking game end:', error);
        }
    }

    /**
     * Get overview analytics
     */
    async getOverview() {
        const today = new Date().toISOString().split('T')[0];

        const todayStats = db.prepare(`
            SELECT 
                COUNT(*) as visitors,
                COUNT(DISTINCT user_id) as uniqueUsers
            FROM page_views
            WHERE date = ?
        `).get(today);

        const allTimeStats = db.prepare(`
            SELECT 
                COUNT(*) as totalVisitors,
                COUNT(DISTINCT user_id) as totalUniqueUsers
            FROM page_views
        `).get();

        const totalPlaytime = db.prepare(`
            SELECT COALESCE(SUM(duration), 0) as total
            FROM sessions
            WHERE duration > 0
        `).get();

        return {
            today: {
                visitors: todayStats.visitors || 0,
                uniqueUsers: todayStats.uniqueUsers || 0
            },
            allTime: {
                totalVisitors: allTimeStats.totalVisitors || 0,
                totalUniqueUsers: allTimeStats.totalUniqueUsers || 0,
                totalPlaytime: Math.floor((totalPlaytime.total || 0) / 1000)
            },
            activeGames: 0 // Can be calculated if needed
        };
    }

    /**
     * Get game-specific analytics
     */
    async getGameAnalytics(gameId) {
        const stats = db.prepare(`
            SELECT 
                COUNT(*) as totalSessions,
                COUNT(DISTINCT user_id) as uniqueUsers,
                COALESCE(SUM(duration), 0) as totalPlaytime,
                COALESCE(AVG(duration), 0) as avgDuration
            FROM sessions
            WHERE game_name = ? AND duration > 0
        `).get(gameId);

        const dailyTrend = db.prepare(`
            SELECT 
                date,
                COUNT(*) as sessions,
                COALESCE(SUM(duration), 0) as playtime
            FROM sessions
            JOIN (
                SELECT DISTINCT date FROM page_views 
                ORDER BY date DESC 
                LIMIT 30
            ) dates ON DATE(sessions.start_time) = dates.date
            WHERE game_name = ?
            GROUP BY date
            ORDER BY date ASC
        `).all(gameId);

        return {
            totalSessions: stats.totalSessions || 0,
            uniqueUsers: stats.uniqueUsers || 0,
            totalPlaytime: Math.floor((stats.totalPlaytime || 0) / 1000),
            avgDuration: (stats.avgDuration || 0) / 1000,
            dailyTrend
        };
    }

    /**
     * Get traffic data with time filtering
     */
    async getTrafficData(range = 'week') {
        let days = 7;
        if (range === 'month') days = 30;
        else if (range === 'today') days = 1;

        const traffic = db.prepare(`
            WITH RECURSIVE dates(date) AS (
                SELECT DATE('now', '-${days - 1} days')
                UNION ALL
                SELECT DATE(date, '+1 day')
                FROM dates
                WHERE date < DATE('now')
            )
            SELECT 
                dates.date,
                COALESCE(COUNT(pv.id), 0) as visitors,
                COALESCE(COUNT(DISTINCT pv.user_id), 0) as uniqueUsers
            FROM dates
            LEFT JOIN page_views pv ON pv.date = dates.date
            GROUP BY dates.date
            ORDER BY dates.date ASC
        `).all();

        return traffic;
    }

    /**
     * Get comparison data for all games
     */
    async getGameComparison() {
        const stats = db.prepare(`
            SELECT 
                game_name,
                COUNT(*) as totalSessions,
                COUNT(DISTINCT user_id) as uniquePlayers,
                COALESCE(SUM(duration), 0) as totalPlaytime,
                COALESCE(AVG(duration), 0) as avgSessionDuration,
                COUNT(DISTINCT DATE(start_time)) as activeDays
            FROM sessions
            WHERE game_name != 'portal' AND duration > 0
            GROUP BY game_name
            ORDER BY totalSessions DESC
        `).all();

        return stats.map(stat => ({
            gameName: stat.game_name,
            totalSessions: stat.totalSessions || 0,
            uniquePlayers: stat.uniquePlayers || 0,
            totalPlaytime: Math.floor((stat.totalPlaytime || 0) / 1000 / 60), // Convert to minutes
            avgSessionDuration: Math.floor((stat.avgSessionDuration || 0) / 1000 / 60), // Convert to minutes
            activeDays: stat.activeDays || 0
        }));
    }

    /**
     * Get device analytics
     */
    async getDeviceAnalytics() {
        const deviceStats = db.prepare(`
            SELECT 
                device_type,
                COUNT(*) as count,
                COUNT(DISTINCT user_id) as uniqueUsers
            FROM sessions
            WHERE device_type IS NOT NULL AND device_type != 'unknown'
            GROUP BY device_type
            ORDER BY count DESC
        `).all();

        const osStats = db.prepare(`
            SELECT 
                os,
                COUNT(*) as count,
                COUNT(DISTINCT user_id) as uniqueUsers
            FROM sessions
            WHERE os IS NOT NULL AND os != 'unknown' AND os != 'other'
            GROUP BY os
            ORDER BY count DESC
        `).all();

        const browserStats = db.prepare(`
            SELECT 
                browser,
                COUNT(*) as count,
                COUNT(DISTINCT user_id) as uniqueUsers
            FROM sessions
            WHERE browser IS NOT NULL AND browser != 'unknown' AND browser != 'other'
            GROUP BY browser
            ORDER BY count DESC
        `).all();

        return {
            devices: deviceStats,
            os: osStats,
            browsers: browserStats
        };
    }

    /**
     * Get user game stats (wins/losses + detailed breakdown)
     */
    async getUserGameStats(userId, gameName) {
        try {
            const sessions = db.prepare(`
                SELECT metrics, duration, start_time
                FROM sessions
                WHERE user_id = ? AND game_name = ? AND metrics IS NOT NULL
            `).all(userId, gameName);

            let wins = 0;
            let losses = 0;
            const detailedStats = {};

            sessions.forEach(session => {
                try {
                    const metrics = JSON.parse(session.metrics);
                    
                    // Check for result in metrics object (nested or direct)
                    const result = metrics.result || (metrics.metrics && metrics.metrics.result);
                    
                    if (result === 'win' || result === 'complete') wins++;
                    else if (result === 'loss' || result === 'lose' || result === 'failed') losses++;

                    // Extract level/difficulty for detailed stats
                    const level = metrics.level || (metrics.metrics && metrics.metrics.level);
                    const difficulty = metrics.difficulty || (metrics.metrics && metrics.metrics.difficulty);
                    const key = level || difficulty;

                    if (key) {
                        if (!detailedStats[key]) {
                            detailedStats[key] = {
                                wins: 0,
                                losses: 0,
                                completions: 0,
                                failures: 0,
                                bestTime: null,
                                totalTime: 0,
                                gamesPlayed: 0,
                                scores: []
                            };
                        }

                        const stat = detailedStats[key];
                        stat.gamesPlayed++;

                        if (result === 'win' || result === 'complete') {
                            stat.wins++;
                            stat.completions++;
                            
                            // Track best time for wins/completions
                            if (session.duration) {
                                const timeInSeconds = Math.floor(session.duration / 1000);
                                if (stat.bestTime === null || timeInSeconds < stat.bestTime) {
                                    stat.bestTime = timeInSeconds;
                                }
                                stat.totalTime += timeInSeconds;
                            }
                        } else if (result === 'loss' || result === 'lose' || result === 'failed') {
                            stat.losses++;
                            stat.failures++;
                        }

                        // Track scores if available
                        const score = metrics.score || (metrics.metrics && metrics.metrics.score);
                        if (score !== undefined && score !== null) {
                            stat.scores.push(score);
                        }
                    }
                } catch (e) {
                    // Ignore parsing errors
                }
            });

            // Calculate derived stats
            Object.keys(detailedStats).forEach(key => {
                const stat = detailedStats[key];
                stat.bestScore = stat.scores.length > 0 ? Math.max(...stat.scores) : null;
                stat.avgTime = stat.completions > 0 ? Math.floor(stat.totalTime / stat.completions) : null;
                // Clean up internal tracking fields
                delete stat.scores;
                delete stat.totalTime;
            });

            return { 
                totalWins: wins, 
                totalLosses: losses,
                detailedStats 
            };
        } catch (error) {
            console.error('Error fetching user game stats:', error);
            return { 
                totalWins: 0, 
                totalLosses: 0,
                detailedStats: {} 
            };
        }
    }

    /**
     * Get public statistics for the landing page
     */
    async getPublicStats() {
        // Active players in last 15 minutes
        const fifteenMinutesAgo = new Date(Date.now() - 15 * 60 * 1000).toISOString();

        // Use a query that doesn't depend on the page_views table having rows
        // to return the subquery results (though if empty, counts will be 0)
        const stats = db.prepare(`
            SELECT 
                (SELECT COUNT(DISTINCT user_id) FROM page_views) as totalPlayers,
                (SELECT COUNT(*) FROM sessions) as gamesPlayed,
                (SELECT COALESCE(SUM(duration), 0) FROM sessions) as totalPlaytime,
                (SELECT COUNT(*) FROM visitors WHERE last_seen > ?) as activePlayers
        `).get(fifteenMinutesAgo);

        return {
            totalPlayers: stats ? stats.totalPlayers : 0,
            activePlayers: stats ? stats.activePlayers : 0,
            gamesPlayed: stats ? stats.gamesPlayed : 0,
            hoursPlayed: stats ? Math.floor(stats.totalPlaytime / 3600000) : 0 // Convert ms to hours
        };
    }

    /**
     * Cleanup old data (optional - keep for compatibility)
     */
    async cleanup() {
        const cutoffDays = 90;
        const cutoffDate = new Date();
        cutoffDate.setDate(cutoffDate.getDate() - cutoffDays);
        const cutoff = cutoffDate.toISOString().split('T')[0];

        try {
            db.prepare('DELETE FROM page_views WHERE date < ?').run(cutoff);
            db.prepare('DELETE FROM sessions WHERE DATE(start_time) < ?').run(cutoff);
            console.log(`Cleaned up data older than ${cutoffDays} days`);
        } catch (error) {
            console.error('Error during cleanup:', error);
        }
    }
}

// Export singleton instance
module.exports = new AnalyticsCollector();
