// User CRUD. Mounted at /api/v1/auth/users by index.js (behind the auth gate).
// Flat access: any logged-in user can manage other users (spec).
import express from 'express';
import pool from '../db/pool.js';
import { hashPassword } from '../auth/passwords.js';
import { DEV_USER_ID } from '../middleware/auth.js';

const router = express.Router();
const MIN_PASSWORD_LEN = 12;

function bad(res, msg) { return res.status(400).json({ error: msg }); }

// GET / — list users (real ones; dev seed hidden)
router.get('/', async (_req, res, next) => {
  try {
    const { rows } = await pool.query(
      `SELECT id, username, display_name, role, last_login_at, created_at
       FROM users WHERE id <> $1 ORDER BY username`, [DEV_USER_ID]);
    res.json(rows);
  } catch (err) { next(err); }
});

// POST / — create user
router.post('/', async (req, res, next) => {
  try {
    const { username, password, display_name, role } = req.body || {};
    if (!username || typeof username !== 'string') return bad(res, 'username required');
    if (!password || password.length < MIN_PASSWORD_LEN) return bad(res, 'password must be at least ' + MIN_PASSWORD_LEN + ' chars');
    const hash = await hashPassword(password);
    const { rows } = await pool.query(
      `INSERT INTO users (username, password_hash, display_name, role)
       VALUES ($1, $2, $3, $4)
       RETURNING id, username, display_name, role, created_at`,
      [username.trim(), hash, display_name || username.trim(), role || 'admin']
    );
    res.status(201).json(rows[0]);
  } catch (err) {
    if (err.code === '23505') return res.status(409).json({ error: 'username already exists' });
    next(err);
  }
});

// POST /:id/password — admin reset another user's password
router.post('/:id/password', async (req, res, next) => {
  try {
    const { new_password } = req.body || {};
    if (!new_password || new_password.length < MIN_PASSWORD_LEN) {
      return bad(res, 'new password must be at least ' + MIN_PASSWORD_LEN + ' chars');
    }
    const hash = await hashPassword(new_password);
    const { rowCount } = await pool.query(
      `UPDATE users SET password_hash = $1, password_updated_at = NOW() WHERE id = $2 AND id <> $3`,
      [hash, req.params.id, DEV_USER_ID]);
    if (rowCount === 0) return res.status(404).json({ error: 'user not found' });
    res.status(204).end();
  } catch (err) { next(err); }
});

// DELETE /:id — delete a user, except the last real user
router.delete('/:id', async (req, res, next) => {
  try {
    if (req.params.id === DEV_USER_ID) return res.status(400).json({ error: 'cannot delete dev user' });
    const { rows } = await pool.query(
      `SELECT COUNT(*)::int AS n FROM users WHERE id <> $1`, [DEV_USER_ID]);
    if (rows[0].n <= 1) return res.status(409).json({ error: 'cannot delete last user' });
    const { rowCount } = await pool.query(`DELETE FROM users WHERE id = $1`, [req.params.id]);
    if (rowCount === 0) return res.status(404).json({ error: 'user not found' });
    res.status(204).end();
  } catch (err) { next(err); }
});

// PATCH /:id { display_name?, role?, password? } — generic update.
// password update goes through hashPassword; other fields are passed through.
router.patch('/:id', async (req, res, next) => {
  try {
    if (req.params.id === DEV_USER_ID) return res.status(400).json({ error: 'cannot edit dev user' });
    const sets = []; const vals = [];
    if (typeof req.body?.display_name === 'string') { sets.push('display_name = $' + (sets.length + 1)); vals.push(req.body.display_name); }
    if (typeof req.body?.role         === 'string') { sets.push('role = $'         + (sets.length + 1)); vals.push(req.body.role); }
    if (typeof req.body?.password     === 'string') {
      if (req.body.password.length < MIN_PASSWORD_LEN) return bad(res, 'password must be at least ' + MIN_PASSWORD_LEN + ' chars');
      sets.push('password_hash = $' + (sets.length + 1) + ', password_updated_at = NOW()');
      vals.push(await hashPassword(req.body.password));
    }
    if (sets.length === 0) return bad(res, 'nothing to update');
    vals.push(req.params.id);
    const { rows } = await pool.query(
      `UPDATE users SET ${sets.join(', ')} WHERE id = $${vals.length} RETURNING id, username, display_name, role`,
      vals
    );
    if (rows.length === 0) return res.status(404).json({ error: 'user not found' });
    res.json(rows[0]);
  } catch (err) { next(err); }
});

export default router;
