import bcrypt from 'bcryptjs';
import { db, id, now } from '../db.js';
import { publicUser } from '../auth.js';

export function listUsers() {
  return db.prepare('SELECT * FROM users ORDER BY display_name').all().map((row) => ({
    ...publicUser(row),
    groups: db.prepare(`
      SELECT g.id, g.name
      FROM groups g
      INNER JOIN user_groups ug ON ug.group_id = g.id
      WHERE ug.user_id = ?
      ORDER BY g.name
    `).all(row.id)
  }));
}

// Provision (or refresh) a user that authenticated through Microsoft Entra.
// Matches on email: an existing account is marked Entra-backed in place so the
// operator keeps their resources, and a brand-new account is created with no
// local password.
export function findOrProvisionEntraUser({ email, displayName }) {
  const normalized = String(email || '').toLowerCase();
  const existing = db.prepare('SELECT * FROM users WHERE email = ?').get(normalized);
  if (existing) {
    db.prepare('UPDATE users SET display_name = ?, auth_provider = ?, updated_at = ? WHERE id = ?')
      .run(displayName || existing.display_name, 'entra', now(), existing.id);
    return db.prepare('SELECT * FROM users WHERE id = ?').get(existing.id);
  }
  const userId = id('usr');
  const timestamp = now();
  // First user on a fresh install becomes admin; subsequent Entra users are standard.
  const isFirstUser = db.prepare('SELECT COUNT(*) AS count FROM users').get().count === 0;
  db.prepare(`
    INSERT INTO users (id, email, display_name, password_hash, auth_provider, role, created_at, updated_at)
    VALUES (?, ?, ?, NULL, 'entra', ?, ?, ?)
  `).run(userId, normalized, displayName || normalized, isFirstUser ? 'admin' : 'user', timestamp, timestamp);
  return db.prepare('SELECT * FROM users WHERE id = ?').get(userId);
}

export function createUser(payload) {
  const userId = id('usr');
  const timestamp = now();
  db.prepare(`
    INSERT INTO users (id, email, display_name, password_hash, auth_provider, role, created_at)
    VALUES (?, ?, ?, ?, 'local', ?, ?)
  `).run(
    userId,
    payload.email.toLowerCase(),
    payload.displayName,
    payload.password ? bcrypt.hashSync(payload.password, 12) : null,
    payload.role,
    timestamp
  );
  const groupStmt = db.prepare('INSERT OR IGNORE INTO user_groups (user_id, group_id) VALUES (?, ?)');
  for (const groupId of payload.groupIds || []) groupStmt.run(userId, groupId);
  return listUsers().find((user) => user.id === userId);
}
