const http = require('http');
const mysql = require('mysql2/promise');
const crypto = require('crypto');

const PORT = 3001;
const ADMIN_PASSWORD = 'rosyshaun';

// Database connection pool
const pool = mysql.createPool({
    host: 'rosy-mariadb',
    user: 'rosy',
    password: 'fakan',
    database: 'practice',
    waitForConnections: true,
    connectionLimit: 10
});

// Generate visitor ID
function generateVisitorId() {
    return crypto.randomBytes(16).toString('hex');
}

// Parse cookies from request
function parseCookies(cookieHeader) {
    const cookies = {};
    if (cookieHeader) {
        cookieHeader.split(';').forEach(cookie => {
            const [name, value] = cookie.trim().split('=');
            if (name && value) cookies[name] = value;
        });
    }
    return cookies;
}

// Parse User-Agent for OS and browser
function parseUserAgent(ua) {
    if (!ua) return { os: 'Unknown', browser: 'Unknown', device_type: 'unknown' };

    let os = 'Unknown';
    let browser = 'Unknown';
    let device_type = 'desktop';

    // OS detection
    if (/iPhone|iPad|iPod/.test(ua)) {
        os = 'iOS';
        device_type = /iPad/.test(ua) ? 'tablet' : 'mobile';
    } else if (/Android/.test(ua)) {
        os = 'Android';
        device_type = /Mobile/.test(ua) ? 'mobile' : 'tablet';
    } else if (/Windows/.test(ua)) {
        os = 'Windows';
    } else if (/Mac OS X/.test(ua)) {
        os = 'macOS';
    } else if (/Linux/.test(ua)) {
        os = 'Linux';
    }

    // Browser detection
    if (/Instagram/.test(ua)) {
        browser = 'Instagram';
    } else if (/FBAN|FBAV/.test(ua)) {
        browser = 'Facebook';
    } else if (/Chrome/.test(ua) && !/Edg/.test(ua)) {
        browser = 'Chrome';
    } else if (/Safari/.test(ua) && !/Chrome/.test(ua)) {
        browser = 'Safari';
    } else if (/Firefox/.test(ua)) {
        browser = 'Firefox';
    } else if (/Edg/.test(ua)) {
        browser = 'Edge';
    }

    return { os, browser, device_type };
}

// Check if likely a bot
function isBot(ua) {
    if (!ua) return false;
    const botPatterns = /bot|crawl|spider|slurp|facebook|whatsapp|telegram|discord|preview|fetch|curl|wget|python|go-http|java/i;
    return botPatterns.test(ua);
}

// Parse JSON body
async function parseBody(req) {
    return new Promise((resolve, reject) => {
        let body = '';
        req.on('data', chunk => body += chunk);
        req.on('end', () => {
            try {
                resolve(body ? JSON.parse(body) : {});
            } catch (e) {
                resolve({});
            }
        });
    });
}

// Parse UTM params from URL
function parseUtmParams(url) {
    try {
        const urlObj = new URL(url, 'https://rosy.shitchell.com');
        return {
            utm_source: urlObj.searchParams.get('utm_source') || null,
            utm_medium: urlObj.searchParams.get('utm_medium') || null,
            utm_campaign: urlObj.searchParams.get('utm_campaign') || null
        };
    } catch {
        return { utm_source: null, utm_medium: null, utm_campaign: null };
    }
}

const server = http.createServer(async (req, res) => {
    // CORS headers
    res.setHeader('Access-Control-Allow-Origin', 'https://rosy.shitchell.com');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
    res.setHeader('Access-Control-Allow-Credentials', 'true');

    if (req.method === 'OPTIONS') {
        res.writeHead(200);
        res.end();
        return;
    }

    const cookies = parseCookies(req.headers.cookie);
    const ip = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || req.socket.remoteAddress;
    const ua = req.headers['user-agent'] || '';

    try {
        // POST /track - Main tracking endpoint
        if (req.method === 'POST' && req.url === '/track') {
            const data = await parseBody(req);
            const { os, browser, device_type } = parseUserAgent(ua);
            const is_bot = isBot(ua) ? 1 : 0;

            let visitorId = cookies['_rv'] || data.visitor_id;
            let isNewVisitor = false;
            let visitorDbId = null;

            // Create or get visitor
            if (visitorId) {
                // Check if visitor exists
                const [rows] = await pool.query(
                    'SELECT id FROM visitors WHERE visitor_hash = ?',
                    [visitorId]
                );
                if (rows.length > 0) {
                    visitorDbId = rows[0].id;
                    // Update last seen and visit count
                    await pool.query(
                        'UPDATE visitors SET last_seen = NOW(), total_visits = total_visits + 1 WHERE id = ?',
                        [visitorDbId]
                    );
                } else {
                    // Cookie exists but not in DB - create new
                    isNewVisitor = true;
                }
            } else {
                // No cookie - new visitor
                visitorId = generateVisitorId();
                isNewVisitor = true;
            }

            if (isNewVisitor) {
                const [result] = await pool.query(
                    `INSERT INTO visitors (visitor_hash, first_ip, os, browser, device_type, is_bot)
                     VALUES (?, ?, ?, ?, ?, ?)`,
                    [visitorId, ip, os, browser, device_type, is_bot]
                );
                visitorDbId = result.insertId;
            }

            // Set cookie (1 year expiry)
            const cookieExpiry = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toUTCString();
            res.setHeader('Set-Cookie', `_rv=${visitorId}; Path=/; Expires=${cookieExpiry}; SameSite=Lax`);

            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({
                success: true,
                visitor_id: visitorId,
                visitor_db_id: visitorDbId,
                is_new: isNewVisitor
            }));
            return;
        }

        // POST /pageview - Record a page view
        if (req.method === 'POST' && req.url === '/pageview') {
            const data = await parseBody(req);
            const { page_url, page_title, referrer, visitor_id } = data;

            // Get visitor DB id
            const [visitors] = await pool.query(
                'SELECT id FROM visitors WHERE visitor_hash = ?',
                [visitor_id]
            );

            if (visitors.length === 0) {
                res.writeHead(400, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Visitor not found' }));
                return;
            }

            const visitorDbId = visitors[0].id;
            const utm = parseUtmParams(page_url);

            // Parse URL into components
            let page_path = null;
            let query_string = null;
            let fragment = null;
            try {
                const urlObj = new URL(page_url);
                page_path = urlObj.pathname;
                query_string = urlObj.search ? urlObj.search.substring(1) : null; // Remove leading ?
                fragment = urlObj.hash ? urlObj.hash.substring(1) : null; // Remove leading #
            } catch (e) {
                // If URL parsing fails, try to extract path manually
                page_path = page_url;
            }

            const [result] = await pool.query(
                `INSERT INTO page_views (visitor_id, ip, page_url, page_path, query_string, fragment, page_title, referrer, utm_source, utm_medium, utm_campaign)
                 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
                [visitorDbId, ip, page_url, page_path, query_string, fragment, page_title, referrer, utm.utm_source, utm.utm_medium, utm.utm_campaign]
            );

            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ success: true, page_view_id: result.insertId }));
            return;
        }

        // POST /event - Record an event
        if (req.method === 'POST' && req.url === '/event') {
            const data = await parseBody(req);
            const { visitor_id, page_view_id, event_type, event_target, event_data, duration } = data;

            // Get visitor DB id
            const [visitors] = await pool.query(
                'SELECT id FROM visitors WHERE visitor_hash = ?',
                [visitor_id]
            );

            if (visitors.length === 0) {
                res.writeHead(400, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Visitor not found' }));
                return;
            }

            const visitorDbId = visitors[0].id;

            await pool.query(
                `INSERT INTO page_events (visitor_id, page_view_id, event_type, event_target, event_data, duration)
                 VALUES (?, ?, ?, ?, ?, ?)`,
                [visitorDbId, page_view_id || null, event_type, event_target, JSON.stringify(event_data || {}), duration || 0]
            );

            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ success: true }));
            return;
        }

        // POST /update - Update page view (time on page, scroll depth)
        if (req.method === 'POST' && req.url === '/update') {
            const data = await parseBody(req);
            const { page_view_id, time_on_page, scroll_depth } = data;

            if (!page_view_id) {
                res.writeHead(400, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'page_view_id required' }));
                return;
            }

            await pool.query(
                `UPDATE page_views SET time_on_page = ?, scroll_depth = ? WHERE id = ?`,
                [time_on_page || 0, scroll_depth || 0, page_view_id]
            );

            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ success: true }));
            return;
        }

        // POST /update-geo - Update page view with GPS geolocation
        if (req.method === 'POST' && req.url === '/update-geo') {
            const data = await parseBody(req);
            const { page_view_id, latitude, longitude, accuracy } = data;

            if (!page_view_id) {
                res.writeHead(400, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'page_view_id required' }));
                return;
            }

            await pool.query(
                `UPDATE page_views SET geo_latitude = ?, geo_longitude = ?, geo_accuracy = ? WHERE id = ?`,
                [latitude || null, longitude || null, accuracy || null, page_view_id]
            );

            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ success: true }));
            return;
        }

        // POST /lookup-ips - Trigger IP geolocation lookup (admin only)
        if (req.method === 'POST' && req.url === '/lookup-ips') {
            const data = await parseBody(req);

            if (data.password !== ADMIN_PASSWORD) {
                res.writeHead(401, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Invalid password' }));
                return;
            }

            // Get IPs that aren't in visitor_ips yet
            const [newIps] = await pool.query(`
                SELECT DISTINCT pv.ip
                FROM page_views pv
                LEFT JOIN visitor_ips vi ON pv.ip = vi.ip
                WHERE vi.ip IS NULL AND pv.ip IS NOT NULL
                LIMIT 45
            `);

            let looked_up = 0;
            for (const row of newIps) {
                try {
                    const response = await fetch(`http://ip-api.com/json/${row.ip}?fields=status,country,regionName,city,isp`);
                    const geo = await response.json();

                    if (geo.status === 'success') {
                        const is_bot = /digitalocean|amazon|google|microsoft|cloudflare|akamai|facebook|line corp/i.test(geo.isp) ? 1 : 0;
                        await pool.query(
                            `INSERT IGNORE INTO visitor_ips (ip, country, region, city, isp, is_bot) VALUES (?, ?, ?, ?, ?, ?)`,
                            [row.ip, geo.country, geo.regionName, geo.city, geo.isp, is_bot]
                        );
                        looked_up++;
                    }
                    // Rate limit: wait 1.5 seconds between requests
                    await new Promise(r => setTimeout(r, 1500));
                } catch (e) {
                    console.error('IP lookup error:', e);
                }
            }

            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ success: true, looked_up, pending: newIps.length }));
            return;
        }

        // GET /stats - Get analytics stats (admin only, password in query)
        if (req.method === 'GET' && req.url.startsWith('/stats')) {
            const urlParams = new URL(req.url, 'http://localhost').searchParams;

            if (urlParams.get('password') !== ADMIN_PASSWORD) {
                res.writeHead(401, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ error: 'Invalid password' }));
                return;
            }

            // Get various stats
            const [totalVisitors] = await pool.query('SELECT COUNT(*) as count FROM visitors WHERE is_bot = 0');
            const [todayVisitors] = await pool.query('SELECT COUNT(*) as count FROM visitors WHERE is_bot = 0 AND DATE(first_seen) = CURDATE()');
            const [returnVisitors] = await pool.query('SELECT COUNT(*) as count FROM visitors WHERE is_bot = 0 AND total_visits > 1');
            const [totalPageViews] = await pool.query('SELECT COUNT(*) as count FROM page_views');
            const [todayPageViews] = await pool.query('SELECT COUNT(*) as count FROM page_views WHERE DATE(viewed_at) = CURDATE()');

            // Top pages (grouped by path, with query string and fragment info)
            const [topPages] = await pool.query(`
                SELECT
                    page_path,
                    COUNT(*) as views,
                    AVG(time_on_page) as avg_time,
                    COUNT(DISTINCT query_string) as unique_query_strings,
                    COUNT(DISTINCT fragment) as unique_fragments
                FROM page_views
                WHERE page_path IS NOT NULL
                GROUP BY page_path
                ORDER BY views DESC
                LIMIT 10
            `);

            // Top locations
            const [topLocations] = await pool.query(`
                SELECT vi.city, vi.country, COUNT(DISTINCT v.id) as visitors
                FROM visitors v
                JOIN page_views pv ON v.id = pv.visitor_id
                JOIN visitor_ips vi ON pv.ip = vi.ip
                WHERE vi.is_bot = 0 AND v.is_bot = 0
                GROUP BY vi.city, vi.country
                ORDER BY visitors DESC
                LIMIT 10
            `);

            // Top referrers
            const [topReferrers] = await pool.query(`
                SELECT
                    COALESCE(utm_source,
                        CASE
                            WHEN referrer LIKE '%instagram%' THEN 'Instagram'
                            WHEN referrer LIKE '%facebook%' THEN 'Facebook'
                            WHEN referrer LIKE '%google%' THEN 'Google'
                            WHEN referrer LIKE '%twitter%' OR referrer LIKE '%t.co%' THEN 'Twitter'
                            WHEN referrer IS NULL OR referrer = '' THEN 'Direct'
                            ELSE 'Other'
                        END
                    ) as source,
                    COUNT(*) as views
                FROM page_views
                GROUP BY source
                ORDER BY views DESC
                LIMIT 10
            `);

            // Recent visitors with all their IP addresses
            const [recentVisitors] = await pool.query(`
                SELECT v.id, v.os, v.browser, v.device_type, v.first_seen, v.last_seen, v.total_visits,
                       MAX(vi.city) as city, MAX(vi.country) as country,
                       GROUP_CONCAT(DISTINCT pv.ip ORDER BY pv.viewed_at SEPARATOR ', ') as ip_addresses
                FROM visitors v
                LEFT JOIN page_views pv ON v.id = pv.visitor_id
                LEFT JOIN visitor_ips vi ON pv.ip = vi.ip
                WHERE v.is_bot = 0
                GROUP BY v.id
                ORDER BY v.last_seen DESC
                LIMIT 20
            `);

            // Top events (photos viewed, etc)
            const [topEvents] = await pool.query(`
                SELECT event_type, event_target, COUNT(*) as count, AVG(duration) as avg_duration
                FROM page_events
                GROUP BY event_type, event_target
                ORDER BY count DESC
                LIMIT 20
            `);

            // Pending IP lookups
            const [pendingIps] = await pool.query(`
                SELECT COUNT(DISTINCT pv.ip) as count
                FROM page_views pv
                LEFT JOIN visitor_ips vi ON pv.ip = vi.ip
                WHERE vi.ip IS NULL AND pv.ip IS NOT NULL
            `);

            // GPS locations (from browser geolocation)
            const [gpsLocations] = await pool.query(`
                SELECT
                    pv.geo_latitude,
                    pv.geo_longitude,
                    pv.geo_accuracy,
                    pv.page_url,
                    pv.viewed_at,
                    v.os,
                    v.browser,
                    v.device_type,
                    vi.city,
                    vi.country
                FROM page_views pv
                JOIN visitors v ON pv.visitor_id = v.id
                LEFT JOIN visitor_ips vi ON pv.ip = vi.ip
                WHERE pv.geo_latitude IS NOT NULL
                ORDER BY pv.viewed_at DESC
                LIMIT 20
            `);

            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({
                summary: {
                    total_visitors: totalVisitors[0].count,
                    today_visitors: todayVisitors[0].count,
                    return_visitors: returnVisitors[0].count,
                    total_page_views: totalPageViews[0].count,
                    today_page_views: todayPageViews[0].count,
                    pending_ip_lookups: pendingIps[0].count
                },
                top_pages: topPages,
                top_locations: topLocations,
                top_referrers: topReferrers,
                recent_visitors: recentVisitors,
                top_events: topEvents,
                gps_locations: gpsLocations
            }));
            return;
        }

        // 404 for everything else
        res.writeHead(404, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'Not found' }));

    } catch (err) {
        console.error('Error:', err);
        res.writeHead(500, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'Server error' }));
    }
});

server.listen(PORT, '0.0.0.0', () => {
    console.log(`Analytics API running on port ${PORT}`);
});
