<?php
// =============================================================
//  POST /api/v1/auth/change_password
//
//  Two entry paths, one validation/update path:
//
//   1. Forced first-login change — mirrors root change_password.php.
//      Body: { "pending_token": "...", "new_password": "...", "confirm_password": "..." }
//      No old password required (the caller only knows a temp password
//      an admin gave them out-of-band).
//
//   2. Voluntary change while already logged in — mirrors
//      app/change_password.php / app/nurse/change_password.php /
//      app/student/change_password.php's shared validation rules.
//      Requires Authorization: Bearer <token>.
//      Body: { "old_password": "...", "new_password": "...", "confirm_password": "..." }
//
//  Either way, on success every existing api_access_tokens row for that
//  account is revoked (security hygiene — same reasoning as a changed
//  password invalidating other browser sessions) and the client must call
//  auth/login.php again with the new password.
// =============================================================

require_once __DIR__ . '/../_bootstrap.php';

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    Api::error(405, 'MethodNotAllowed', 'Use POST');
}

$body            = Api::body();
$newPassword     = (string)($body['new_password']     ?? '');
$confirmPassword = (string)($body['confirm_password'] ?? '');
$pendingToken    = isset($body['pending_token']) ? (string)$body['pending_token'] : null;

if ($newPassword === '' || $confirmPassword === '') {
    Api::error(422, 'ValidationError', 'New password and confirmation are required');
}
if ($newPassword !== $confirmPassword) {
    Api::error(422, 'ValidationError', 'New password and confirmation do not match');
}
if (strlen($newPassword) < 6) {
    Api::error(422, 'ValidationError', 'New password must be at least 6 characters');
}

if ($pendingToken !== null) {
    // ── Path 1: forced first-login change ───────────────────────────────────
    $pending = PendingAuthToken::verify($pendingToken, 'password_change');
    if (!$pending) {
        Api::error(401, 'InvalidPendingToken', 'This step has expired. Please log in again.');
    }
    $table = $pending['table'];
    $id    = (int)$pending['id'];

} else {
    // ── Path 2: voluntary change, already authenticated ─────────────────────
    $account = api_authenticate();
    $table   = $account->getTable();
    $id      = $account->getId();

    $oldPassword = (string)($body['old_password'] ?? '');
    if ($oldPassword === '') {
        Api::error(422, 'ValidationError', 'Current password is required');
    }
    if ($oldPassword === $newPassword) {
        Api::error(422, 'ValidationError', 'New password must be different from your current password');
    }

    $stmt = $conn->prepare("SELECT password FROM `{$table}` WHERE id = ? AND status = 'Active'");
    $stmt->bind_param('i', $id);
    $stmt->execute();
    $row = $stmt->get_result()->fetch_assoc();
    $stmt->close();

    if (!$row || !password_verify($oldPassword, $row['password'])) {
        Api::error(401, 'InvalidCredentials', 'Current password is incorrect');
    }
}

$hashed = password_hash($newPassword, PASSWORD_DEFAULT);
$stmt   = $conn->prepare("UPDATE `{$table}` SET password = ?, password_change_required = 0 WHERE id = ?");
$stmt->bind_param('si', $hashed, $id);
$ok = $stmt->execute();
$stmt->close();

if (!$ok) {
    Api::error(500, 'UpdateFailed', 'Failed to update password. Please try again.');
}

$token_manager->revokeAllForAccount($table, $id);

Api::success([
    'status'  => 'password_changed',
    'message' => 'Password changed. Please log in again with your new password.',
]);
