/**
 * SSO User Model
 *
 * sso_users 테이블 CRUD 및 비밀번호 검증
 * bcrypt + pbkdf2_sha256 둘 다 지원
 */

const mysql = require('mysql2/promise');
const bcrypt = require('bcrypt');
const crypto = require('crypto');

let pool;

function getPool() {
  if (!pool) {
    pool = mysql.createPool({
      host: process.env.DB_HOST || 'mariadb',
      port: parseInt(process.env.DB_PORT) || 3306,
      user: process.env.DB_USER || 'hyungi_user',
      password: process.env.DB_PASSWORD,
      database: process.env.DB_NAME || 'hyungi',
      waitForConnections: true,
      connectionLimit: 10,
      queueLimit: 0
    });
  }
  return pool;
}

/**
 * pbkdf2_sha256 해시 검증 (M-Project/passlib 호환)
 * passlib 형식: $pbkdf2-sha256$rounds$salt$hash
 */
function verifyPbkdf2(password, storedHash) {
  try {
    const parts = storedHash.split('$');
    if (parts.length < 5) return false;

    const rounds = parseInt(parts[2]);
    // passlib uses adapted base64 (. instead of +, no padding)
    const salt = parts[3].replace(/\./g, '+');
    const hash = parts[4].replace(/\./g, '+');

    // Pad base64 if needed
    const padded = (s) => s + '='.repeat((4 - s.length % 4) % 4);

    const saltBuffer = Buffer.from(padded(salt), 'base64');
    const expectedHash = Buffer.from(padded(hash), 'base64');

    const derivedKey = crypto.pbkdf2Sync(password, saltBuffer, rounds, expectedHash.length, 'sha256');
    return crypto.timingSafeEqual(derivedKey, expectedHash);
  } catch (err) {
    console.error('pbkdf2 verify error:', err.message);
    return false;
  }
}

/**
 * 비밀번호 검증 (bcrypt 또는 pbkdf2_sha256 자동 감지)
 */
async function verifyPassword(password, storedHash) {
  if (!password || !storedHash) return false;

  // pbkdf2-sha256 형식 (passlib)
  if (storedHash.startsWith('$pbkdf2-sha256$')) {
    return verifyPbkdf2(password, storedHash);
  }

  // bcrypt 형식
  if (storedHash.startsWith('$2b$') || storedHash.startsWith('$2a$')) {
    return bcrypt.compare(password, storedHash);
  }

  return false;
}

/**
 * bcrypt로 비밀번호 해시 생성 (새 비밀번호는 항상 bcrypt)
 */
async function hashPassword(password) {
  return bcrypt.hash(password, 10);
}

async function findByUsername(username) {
  const db = getPool();
  const [rows] = await db.query(
    `SELECT s.*, d.department_id, d.department_name, d.is_production
     FROM sso_users s
     LEFT JOIN departments d ON s.department_id = d.department_id
     WHERE s.username = ? AND s.is_active = TRUE`,
    [username]
  );
  return rows[0] || null;
}

async function findById(userId) {
  const db = getPool();
  const [rows] = await db.query(
    `SELECT s.*, d.department_id, d.department_name, d.is_production
     FROM sso_users s
     LEFT JOIN departments d ON s.department_id = d.department_id
     WHERE s.user_id = ?`,
    [userId]
  );
  return rows[0] || null;
}

async function findAll() {
  const db = getPool();
  const [rows] = await db.query(
    'SELECT user_id, username, name, department, role, system1_access, system2_access, system3_access, is_active, last_login, created_at FROM sso_users ORDER BY user_id'
  );
  return rows;
}

async function create({ username, password, name, department, role }) {
  const db = getPool();
  const password_hash = await hashPassword(password);
  const [result] = await db.query(
    `INSERT INTO sso_users (username, password_hash, name, department, role)
     VALUES (?, ?, ?, ?, ?)`,
    [username, password_hash, name || null, department || null, role || 'user']
  );
  return findById(result.insertId);
}

async function update(userId, data) {
  const db = getPool();
  const fields = [];
  const values = [];

  if (data.name !== undefined) { fields.push('name = ?'); values.push(data.name); }
  if (data.department !== undefined) { fields.push('department = ?'); values.push(data.department); }
  if (data.role !== undefined) { fields.push('role = ?'); values.push(data.role); }
  if (data.system1_access !== undefined) { fields.push('system1_access = ?'); values.push(data.system1_access); }
  if (data.system2_access !== undefined) { fields.push('system2_access = ?'); values.push(data.system2_access); }
  if (data.system3_access !== undefined) { fields.push('system3_access = ?'); values.push(data.system3_access); }
  if (data.is_active !== undefined) { fields.push('is_active = ?'); values.push(data.is_active); }
  if (data.password) {
    fields.push('password_hash = ?');
    values.push(await hashPassword(data.password));
  }

  if (fields.length === 0) return findById(userId);

  values.push(userId);
  await db.query(
    `UPDATE sso_users SET ${fields.join(', ')} WHERE user_id = ?`,
    values
  );
  return findById(userId);
}

async function updateLastLogin(userId) {
  const db = getPool();
  await db.query(
    'UPDATE sso_users SET last_login = NOW() WHERE user_id = ?',
    [userId]
  );
}

async function deleteUser(userId) {
  const db = getPool();
  await db.query('UPDATE sso_users SET is_active = FALSE WHERE user_id = ?', [userId]);
}

module.exports = {
  verifyPassword,
  hashPassword,
  findByUsername,
  findById,
  findAll,
  create,
  update,
  updateLastLogin,
  deleteUser,
  getPool
};
