import { audit, withTransaction } from './db.js';
import { assertStrongPassword, hashPassword, verifyPassword } from './passwords.js';
import { nowIso, sanitizeText, uuid } from './utils.js';

function normalizeEmail(value) {
  const email = String(value || '').trim().toLowerCase();
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) throw Object.assign(new Error('Geçerli bir yönetici e-posta adresi girin.'), { code: 'INVALID_ADMIN_EMAIL', status: 400 });
  return email;
}

export function createInitialAdmin(db, input = {}, ip = '') {
  const count = Number(db.prepare('SELECT COUNT(*) AS count FROM admin_users').get().count || 0);
  if (count > 0) throw Object.assign(new Error('İlk yönetici hesabı zaten oluşturulmuş.'), { code: 'ADMIN_ALREADY_EXISTS', status: 409 });
  const email = normalizeEmail(input.email);
  const name = sanitizeText(input.name || 'OnlyCoin Administrator', 80);
  const password = assertStrongPassword(input.password, { minLength: 14, label: 'Yönetici parolası' });
  if (password !== String(input.confirmPassword || '')) throw Object.assign(new Error('Yönetici parolaları eşleşmiyor.'), { code: 'PASSWORD_MISMATCH', status: 400 });
  const hashed = hashPassword(password);
  const now = nowIso();
  const id = uuid();
  withTransaction(db, () => {
    db.prepare(`INSERT INTO admin_users(id,email,name,password_hash,password_salt,password_params_json,role,status,failed_attempts,locked_until,last_login_at,created_at,updated_at)
      VALUES(?,?,?,?,?,?,'owner','active',0,NULL,NULL,?,?)`)
      .run(id, email, name, hashed.hash, hashed.salt, JSON.stringify(hashed.params), now, now);
    audit(db, { actorType: 'installer', actorId: 'installer', action: 'admin.initial.create', targetType: 'admin_user', targetId: id, after: { email, name, role: 'owner' }, ip });
  });
  return publicAdmin(db.prepare('SELECT * FROM admin_users WHERE id=?').get(id));
}

export function authenticateAdmin(db, input = {}, ip = '') {
  const email = normalizeEmail(input.email);
  const row = db.prepare('SELECT * FROM admin_users WHERE lower(email)=?').get(email);
  const nowSeconds = Math.floor(Date.now() / 1000);
  if (!row || row.status !== 'active') throw Object.assign(new Error('Yönetici e-posta adresi veya parolası geçersiz.'), { code: 'INVALID_ADMIN_CREDENTIALS', status: 401 });
  if (row.locked_until && Number(row.locked_until) > nowSeconds) {
    throw Object.assign(new Error('Yönetici hesabı geçici olarak kilitli.'), { code: 'ADMIN_LOCKED', status: 423, details: { retryAfter: Number(row.locked_until) - nowSeconds } });
  }
  if (!verifyPassword(input.password, row)) {
    const attempts = Number(row.failed_attempts || 0) + 1;
    const lockedUntil = attempts >= 5 ? nowSeconds + 15 * 60 : null;
    db.prepare('UPDATE admin_users SET failed_attempts=?,locked_until=?,updated_at=? WHERE id=?').run(attempts, lockedUntil, nowIso(), row.id);
    audit(db, { actorType: 'anonymous', actorId: email, action: 'admin.login.failed', targetType: 'admin_user', targetId: row.id, ip });
    throw Object.assign(new Error('Yönetici e-posta adresi veya parolası geçersiz.'), { code: 'INVALID_ADMIN_CREDENTIALS', status: 401 });
  }
  db.prepare('UPDATE admin_users SET failed_attempts=0,locked_until=NULL,last_login_at=?,updated_at=? WHERE id=?').run(nowIso(), nowIso(), row.id);
  audit(db, { actorType: 'admin', actorId: row.id, action: 'admin.login.success', targetType: 'admin_user', targetId: row.id, ip });
  return publicAdmin(db.prepare('SELECT * FROM admin_users WHERE id=?').get(row.id));
}

export function publicAdmin(row) {
  if (!row) return null;
  return { id: row.id, email: row.email, name: row.name, role: row.role, status: row.status, lastLoginAt: row.last_login_at, createdAt: row.created_at };
}

export function getAdmin(db, id) {
  return publicAdmin(db.prepare('SELECT * FROM admin_users WHERE id=?').get(id));
}
