const bcrypt = require('bcryptjs');
const jwt    = require('jsonwebtoken');
const db     = require('../db/db');
const { BCRYPT_ROUNDS } = require('../config');
const { stripTags } = require('../utils/sanitize');

function signToken(user) {
  return jwt.sign(
    { id: user.id, email: user.email, role: user.role, name: user.name, tv: user.token_version || 0 },
    process.env.JWT_SECRET,
    { algorithm: 'HS256', expiresIn: process.env.JWT_EXPIRES_IN || '7d' }
  );
}

async function register(req, res, next) {
  try {
    const { password, name } = req.body;
    const email = req.body.email?.trim().toLowerCase();

    if (!email || !password || !name)
      return res.status(400).json({ error: 'email, password and name are required' });
    if (password.length < 8)
      return res.status(400).json({ error: 'Password must be at least 8 characters' });

    if (db.prepare('SELECT id FROM users WHERE email = ?').get(email))
      return res.status(409).json({ error: 'Email already registered' });

    const cleanName = stripTags(name.trim());
    const hash = await bcrypt.hash(password, BCRYPT_ROUNDS);
    let lastInsertRowid;
    try {
      ({ lastInsertRowid } = db.prepare(
        'INSERT INTO users (email, password_hash, name) VALUES (?, ?, ?)'
      ).run(email, hash, cleanName));
    } catch (e) {
      if (e.message?.includes('UNIQUE')) return res.status(409).json({ error: 'Email already registered' });
      throw e;
    }

    const user  = db.prepare('SELECT id, email, name, role FROM users WHERE id = ?').get(lastInsertRowid);
    const token = signToken(user);
    res.status(201).json({ token, user });
  } catch (err) { next(err); }
}

async function login(req, res, next) {
  try {
    const { password } = req.body;
    const email = req.body.email?.trim().toLowerCase();
    if (!email || !password)
      return res.status(400).json({ error: 'email and password are required' });

    const user = db.prepare(
      'SELECT id, email, name, role, password_hash, token_version, avatar_url FROM users WHERE email = ?'
    ).get(email);

    if (!user || !(await bcrypt.compare(password, user.password_hash)))
      return res.status(401).json({ error: 'Invalid credentials' });

    db.prepare("UPDATE users SET last_login = datetime('now') WHERE id = ?").run(user.id);

    const token = signToken(user);
    res.json({ token, user: { id: user.id, email: user.email, name: user.name, role: user.role, avatar_url: user.avatar_url } });
  } catch (err) { next(err); }
}

function me(req, res) {
  const user = db.prepare(
    'SELECT id, email, name, role, created_at, last_login, avatar_url FROM users WHERE id = ?'
  ).get(req.user.id);
  res.json(user);
}

async function updateProfile(req, res, next) {
  try {
    const { name, currentPassword, newPassword } = req.body;
    const user = db.prepare('SELECT id, name, email, role, password_hash FROM users WHERE id = ?').get(req.user.id);

    if (name?.trim() && name.trim() !== user.name) {
      db.prepare('UPDATE users SET name = ? WHERE id = ?').run(stripTags(name.trim()), user.id);
    }

    if (newPassword) {
      if (!currentPassword) return res.status(400).json({ error: 'Текущий пароль обязателен' });
      const valid = await bcrypt.compare(currentPassword, user.password_hash);
      if (!valid) return res.status(401).json({ error: 'Неверный текущий пароль' });
      if (newPassword.length < 8) return res.status(400).json({ error: 'Пароль минимум 8 символов' });
      const hash = await bcrypt.hash(newPassword, BCRYPT_ROUNDS);
      db.prepare('UPDATE users SET password_hash = ?, token_version = token_version + 1 WHERE id = ?').run(hash, user.id);
    }

    const updated = db.prepare('SELECT id, email, name, role, created_at, token_version FROM users WHERE id = ?').get(user.id);
    const token = signToken(updated);
    res.json({ user: updated, token });
  } catch (err) { next(err); }
}

module.exports = { register, login, me, updateProfile };
