const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

const loginAttempts = new Map();
const RATE_LIMIT_WINDOW = 15 * 60 * 1000;
const MAX_LOGIN_ATTEMPTS = 5;
const CLEANUP_INTERVAL = 15 * 60 * 1000;

function checkRateLimit(ip) {
    const now = Date.now();
    const record = loginAttempts.get(ip);
    if (!record) {
        loginAttempts.set(ip, { count: 1, firstAttempt: now });
        return true;
    }
    if (now - record.firstAttempt > RATE_LIMIT_WINDOW) {
        loginAttempts.set(ip, { count: 1, firstAttempt: now });
        return true;
    }
    if (record.count >= MAX_LOGIN_ATTEMPTS) {
        return false;
    }
    record.count++;
    return true;
}

function clearRateLimit(ip) {
    loginAttempts.delete(ip);
}

function cleanupLoginAttempts() {
    const now = Date.now();
    for (const [ip, record] of loginAttempts.entries()) {
        if (now - record.firstAttempt > RATE_LIMIT_WINDOW) {
            loginAttempts.delete(ip);
        }
    }
}

setInterval(cleanupLoginAttempts, CLEANUP_INTERVAL);

let db;
let JWT_SECRET;

function init(database, jwtSecret) {
    db = database;
    JWT_SECRET = jwtSecret;
}

function authenticateToken(req, res, next) {
    const authHeader = req.headers['authorization'];
    const token = authHeader && authHeader.split(' ')[1];
    if (!token) return res.status(401).json({ error: 'Unauthorized' });
    jwt.verify(token, JWT_SECRET, (err, user) => {
        if (err) return res.status(403).json({ error: 'Invalid or expired token' });
        req.user = user;
        next();
    });
}

function requireAdmin(req, res, next) {
    if (req.user.role !== 'admin') return res.status(403).json({ error: 'Admin access required' });
    next();
}

function login(req, res) {
    const clientIp = req.ip || req.connection.remoteAddress || 'unknown';
    
    if (!checkRateLimit(clientIp)) {
        return res.status(429).json({ error: 'Слишком много попыток входа. Попробуйте через 15 минут.' });
    }
    
    const { login, password } = req.body;
    if (!login || !password) return res.status(400).json({ error: 'Login and password required' });
    db.get(`SELECT id, login, password_hash, full_name, email, role FROM users WHERE login = ?`, [login], (err, user) => {
        if (err) return res.status(500).json({ error: 'Database error' });
        if (!user) return res.status(401).json({ error: 'Invalid credentials' });
        const match = bcrypt.compareSync(password, user.password_hash);
        if (!match) return res.status(401).json({ error: 'Invalid credentials' });
        
        clearRateLimit(clientIp);
        
        const token = jwt.sign({ id: user.id, login: user.login, role: user.role }, JWT_SECRET, { expiresIn: '24h' });
        res.json({
            token,
            user: { id: user.id, login: user.login, full_name: user.full_name, email: user.email, role: user.role }
        });
    });
}

function updateProfile(req, res) {
    const { full_name, email } = req.body;
    db.run(`UPDATE users SET full_name = COALESCE(?, full_name), email = COALESCE(?, email) WHERE id = ?`,
        [full_name || null, email || null, req.user.id], function(err) {
            if (err) return res.status(500).json({ error: 'Database error' });
            db.get(`SELECT id, login, full_name, email, role FROM users WHERE id = ?`, [req.user.id], (err, row) => {
                if (err) return res.status(500).json({ error: 'Database error' });
                res.json({ message: 'Profile updated', user: row });
            });
        });
}

function changePassword(req, res) {
    const { current_password, new_password } = req.body;
    if (!current_password || !new_password) return res.status(400).json({ error: 'Current and new password required' });
    if (new_password.length < 6) return res.status(400).json({ error: 'Password must be at least 6 characters' });
    db.get(`SELECT password_hash FROM users WHERE id = ?`, [req.user.id], (err, row) => {
        if (err) return res.status(500).json({ error: 'Database error' });
        if (!row) return res.status(404).json({ error: 'User not found' });
        const match = bcrypt.compareSync(current_password, row.password_hash);
        if (!match) return res.status(401).json({ error: 'Current password is incorrect' });
        const hash = bcrypt.hashSync(new_password, 10);
        db.run(`UPDATE users SET password_hash = ? WHERE id = ?`, [hash, req.user.id], (err) => {
            if (err) return res.status(500).json({ error: 'Database error' });
            res.json({ message: 'Password changed successfully' });
        });
    });
}

function setupRoutes(app) {
    app.post('/api/auth/login', login);
    app.put('/api/auth/me', authenticateToken, updateProfile);
    app.post('/api/auth/change-password', authenticateToken, changePassword);
}

module.exports = { init, setupRoutes, authenticateToken, requireAdmin, login };