const express = require('express');
const nunjucks = require('nunjucks');
const path = require('path');
const parser = require('cookie-parser');

const database = require('./storage/database');

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

const version = process.env.VERSION;
const vBuild = process.env.VERSION_BUILD;
const vState = process.env.VERSION_STATE;

// ─── SICUREZZA GLOBALE ──────────────────────────────────────────────

// Trust proxy (necessario dietro Nginx/Traefik per avere il vero IP del client)
app.set('trust proxy', 1);

// Rate Limiter in-memory (protezione DoS base, senza dipendenze esterne)
const rateLimitStore = new Map();
const RATE_LIMIT_WINDOW_MS = 60 * 1000; // 1 minuto
const RATE_LIMIT_MAX = 100; // max richieste per finestra
const RATE_LIMIT_AUTH_MAX = 10; // max tentativi login/register per finestra

// Pulizia periodica dello store
setInterval(() => {
    const now = Date.now();
    for (const [key, entry] of rateLimitStore) {
        if (now - entry.start > RATE_LIMIT_WINDOW_MS) {
            rateLimitStore.delete(key);
        }
    }
}, RATE_LIMIT_WINDOW_MS);

function createRateLimiter(maxRequests) {
    return (req, res, next) => {
        const key = `${req.ip}:${maxRequests}`;
        const now = Date.now();
        const entry = rateLimitStore.get(key);

        if (!entry || now - entry.start > RATE_LIMIT_WINDOW_MS) {
            rateLimitStore.set(key, { count: 1, start: now });
            return next();
        }

        entry.count++;
        if (entry.count > maxRequests) {
            res.set('Retry-After', Math.ceil((RATE_LIMIT_WINDOW_MS - (now - entry.start)) / 1000));
            return res.status(429).json({ error: 'Troppe richieste, riprova più tardi' });
        }

        next();
    };
}

const globalRateLimit = createRateLimiter(RATE_LIMIT_MAX);
const authRateLimit = createRateLimiter(RATE_LIMIT_AUTH_MAX);

// Security headers (equivalente leggero di Helmet, senza dipendenze)
app.use((req, res, next) => {
    res.setHeader('X-Content-Type-Options', 'nosniff');
    res.setHeader('X-Frame-Options', 'DENY');
    res.setHeader('X-XSS-Protection', '0');
    res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
    res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
    res.setHeader(
        'Content-Security-Policy',
        "default-src 'self'; style-src 'self'; script-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'"
    );
    res.removeHeader('X-Powered-By');
    next();
});

// Rate limit globale
app.use(globalRateLimit);

// Limiti dimensione body per prevenire payload eccessivi
app.use(express.json({ limit: '16kb' }));
app.use(express.urlencoded({ extended: true, limit: '16kb' }));
app.use(parser());

// ─── STATIC FILES ───────────────────────────────────────────────────
const staticFolder = path.join(__dirname, 'static');
app.use('/static', express.static(staticFolder));
app.use('/api/static', express.static(staticFolder));

// ─── NUNJUCKS TEMPLATES ─────────────────────────────────────────────
const templatesFolder = path.join(__dirname, 'templates');
nunjucks.configure(templatesFolder, {
    autoescape: true,
    express: app,
    noCache: true,
    watch: false
});
app.set('views', templatesFolder);
app.set('view engine', 'html');

// ─── ROUTES ─────────────────────────────────────────────────────────

// Views (pagine HTML)
app.use('/', require('./routes/views/auth'));
app.use('/sessions', require('./routes/views/sessions'));
app.use('/user', require('./routes/views/user'));

// API - Auth (con rate limit più stretto su login/register)
const authRoutes = require('./routes/auth');
app.use('/api/auth/login', authRateLimit);
app.use('/api/auth/register', authRateLimit);
app.use('/api/auth', authRoutes);

// API - Risorse
app.use('/api/users', require('./routes/users'));
app.use('/api/sessions', require('./routes/sessions'));

// ─── HEALTH CHECK ───────────────────────────────────────────────────
app.get('/health', async (req, res) => {
    const dbConnected = await database.checkPostgres();
    const redisHelper = require('./storage/redis');
    const redisConnected = await redisHelper.checkRedis();

    res.json({
        status: dbConnected && redisConnected ? "ok" : "degraded",
        service: "auth",
        database: dbConnected ? "connected" : "disconnected",
        redis: redisConnected ? "connected" : "disconnected",
        version: version,
        build_number: vBuild,
        version_state: vState
    });
});

// ─── 404 HANDLER ────────────────────────────────────────────────────
app.use((req, res) => {
    res.status(404).json({ error: 'Risorsa non trovata' });
});

// ─── ERROR HANDLER GLOBALE ──────────────────────────────────────────
app.use((err, req, res, _next) => {
    console.error('[ERROR]', err.message, '| code:', err.code);
    res.status(500).json({ error: 'Errore interno del server' });
});

// ─── STARTUP ────────────────────────────────────────────────────────
async function start() {
    await database.initDb();
    app.listen(PORT, '0.0.0.0', () => {
        console.log(`[AUTH] Started on port ${PORT}`);
    });
}

start().catch(err => {
    console.error('[AUTH] Failed to start:', err);
    process.exit(1);
});
