const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const compression = require('compression');
const morgan = require('morgan');
const fs = require('fs').promises;
const path = require('path');

const app = express();
const PORT = process.env.PORT || 3000;

// Простой rate limiting
const requestCounts = new Map();
const RATE_LIMIT = 100; // 100 запросов
const RATE_LIMIT_WINDOW = 60000; // за 1 минуту

function rateLimit(req, res, next) {
    const ip = req.ip;
    const now = Date.now();
    const windowStart = now - RATE_LIMIT_WINDOW;

    if (!requestCounts.has(ip)) {
        requestCounts.set(ip, []);
    }

    const requests = requestCounts.get(ip);
    // Удаляем старые запросы
    const recentRequests = requests.filter(time => time > windowStart);

    if (recentRequests.length >= RATE_LIMIT) {
        return res.status(429).json({
            error: 'Too Many Requests',
            retryAfter: Math.ceil((requests[0] + RATE_LIMIT_WINDOW - now) / 1000)
        });
    }

    recentRequests.push(now);
    requestCounts.set(ip, recentRequests);
    next();
}

// Middleware
app.use(helmet({
    crossOriginResourcePolicy: { policy: "cross-origin" }
}));
app.use(compression());
app.use(cors());
app.use(express.json({ limit: '1mb' }));

// Логирование запросов в файл
const accessLogStream = require('fs').createWriteStream(
    path.join(__dirname, 'logs', 'access.log'),
    { flags: 'a' }
);
app.use(morgan('combined', { stream: accessLogStream }));

// Простой логгер
const logger = {
    info: (message, meta = {}) => {
        console.log(`[INFO] ${message}`, JSON.stringify(meta));
    },
    error: (message, meta = {}) => {
        console.error(`[ERROR] ${message}`, JSON.stringify(meta));
    }
};

// Функция для записи аналитики в файл
async function writeAnalytics(data) {
    try {
        const timestamp = new Date().toISOString().split('T')[0];
        const logFile = path.join(__dirname, 'data', `analytics-${timestamp}.json`);

        const logEntry = {
            receivedAt: new Date().toISOString(),
            ...data
        };

        // Читаем существующие данные
        let existingData = [];
        try {
            const fileContent = await fs.readFile(logFile, 'utf8');
            existingData = JSON.parse(fileContent);
        } catch (error) {
            // Файл не существует или пустой - это нормально
        }

        // Добавляем новую запись
        existingData.push(logEntry);

        // Записываем обратно
        await fs.writeFile(logFile, JSON.stringify(existingData, null, 2));

        logger.info('Analytics event saved', {
            eventsCount: data.events?.length || 1,
            sessionId: data.sessionId
        });

        return true;
    } catch (error) {
        logger.error('Error writing analytics data', { error: error.message });
        throw error;
    }
}

// Роуты
app.get('/health', (req, res) => {
    res.json({
        status: 'OK',
        timestamp: new Date().toISOString(),
        service: 'analytics-server',
        version: '1.0.0'
    });
});

app.post('/analytics', rateLimit, async (req, res) => {
    try {
        const { events, sessionId } = req.body;

        if (!events || !Array.isArray(events)) {
            return res.status(400).json({
                error: 'Invalid data format: events array required'
            });
        }

        await writeAnalytics({ events, sessionId });

        res.json({
            success: true,
            received: events.length,
            sessionId
        });

        logger.info('Analytics data received', {
            count: events.length,
            sessionId: sessionId
        });
    } catch (error) {
        logger.error('Analytics processing error', { error: error.message });
        res.status(500).json({
            success: false,
            error: 'Internal server error'
        });
    }
});

// Статистика
app.get('/stats', async (req, res) => {
    try {
        const dataDir = path.join(__dirname, 'data');

        // Проверяем существует ли директория
        try {
            await fs.access(dataDir);
        } catch {
            return res.json({ totalEvents: 0, filesCount: 0, uniqueSessions: 0 });
        }

        const files = await fs.readdir(dataDir);
        const analyticsFiles = files.filter(f => f.startsWith('analytics-'));

        let totalEvents = 0;
        const sessions = new Set();

        for (const file of analyticsFiles.slice(-7)) { // Последние 7 дней
            try {
                const content = await fs.readFile(path.join(dataDir, file), 'utf8');
                const data = JSON.parse(content);

                data.forEach(entry => {
                    totalEvents += entry.events?.length || 0;
                    if (entry.sessionId) sessions.add(entry.sessionId);
                });
            } catch (error) {
                logger.error('Error reading analytics file', { file, error: error.message });
            }
        }

        res.json({
            totalEvents,
            uniqueSessions: sessions.size,
            filesCount: analyticsFiles.length,
            lastUpdated: new Date().toISOString()
        });
    } catch (error) {
        logger.error('Stats error', { error: error.message });
        res.status(500).json({ error: error.message });
    }
});

// Информация о сервисе
app.get('/info', (req, res) => {
    res.json({
        service: 'analytics-server',
        version: '1.0.0',
        status: 'running',
        endpoints: [
            'POST /api/analytics - Send analytics events',
            'GET /api/stats - Get statistics',
            'GET /health - Health check'
        ]
    });
});

// Обработка 404
app.use((req, res) => {
    res.status(404).json({ error: 'Route not found' });
});

// Обработка ошибок
app.use((error, req, res, next) => {
    logger.error('Unhandled error', { error: error.message });
    res.status(500).json({ error: 'Internal server error' });
});

// Создаем необходимые директории при запуске
async function initialize() {
    try {
        await fs.mkdir(path.join(__dirname, 'logs'), { recursive: true });
        await fs.mkdir(path.join(__dirname, 'data'), { recursive: true });
        logger.info('Directories initialized');
    } catch (error) {
        logger.error('Directory initialization failed', { error: error.message });
    }
}

app.listen(PORT, '0.0.0.0', async () => {
    await initialize();
    logger.info(`Analytics server running on port ${PORT}`);
    console.log(`🔍 Analytics server: http://localhost:${PORT}`);
    console.log(`📊 Health check: http://localhost:${PORT}/health`);
    console.log(`📈 Stats: http://localhost:${PORT}/api/stats`);
});