<?php
/**
 * license-php/api/admin-change-password.php
 * POST /api/admin/change-password
 * Security Remediation (SEC-AUTH-01): Strictly authenticated and authorized.
 * Only authenticated administrators (role: admin, developer, super_admin) are permitted.
 * Passwords are cryptographically hashed using standard Bcrypt.
 */

require_once __DIR__ . '/../lib/Response.php';
require_once __DIR__ . '/../lib/LicenseCrypto.php';

Response::handleCors();

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    Response::json(405, ['success' => false, 'code' => 'METHOD_NOT_ALLOWED', 'message' => 'Method Not Allowed']);
}

// 1. Extract authentication token
$token = $_COOKIE['presensi_auth'] ?? '';
if (!$token && isset($_SERVER['HTTP_AUTHORIZATION'])) {
    $token = trim((string)preg_replace('/^Bearer\s+/i', '', $_SERVER['HTTP_AUTHORIZATION']));
}

if (!$token) {
    Response::json(401, [
        'success' => false,
        'code'    => 'UNAUTHENTICATED',
        'message' => 'Akses ditolak: Autentikasi administrator diperlukan untuk mengubah password.'
    ]);
}

// 2. Cryptographic token verification
$config = require __DIR__ . '/../config/config.php';
$pubKeyPath = $config['keys']['public'] ?? (dirname(__DIR__, 2) . '/keys/license_public.key');

if (!file_exists($pubKeyPath)) {
    Response::json(500, ['success' => false, 'code' => 'CRYPTO_ERROR', 'message' => 'Kunci publik lisensi server tidak ditemukan.']);
}

$pubKeyPem = file_get_contents($pubKeyPath);
$verified = LicenseCrypto::verifyToken($token, $pubKeyPem);

if (!$verified || !$verified['valid']) {
    Response::json(401, [
        'success' => false,
        'code'    => 'INVALID_TOKEN',
        'message' => 'Token autentikasi tidak valid.'
    ]);
}

if (!empty($verified['payload']['exp']) && $verified['payload']['exp'] < time()) {
    Response::json(401, [
        'success' => false,
        'code'    => 'EXPIRED_TOKEN',
        'message' => 'Token autentikasi telah kedaluwarsa.'
    ]);
}

// 3. Strict Role-Based Authorization
$role = $verified['payload']['role'] ?? '';
if (!in_array($role, ['admin', 'developer', 'super_admin'], true)) {
    Response::json(403, [
        'success' => false,
        'code'    => 'FORBIDDEN',
        'message' => 'Akses ditolak: Anda tidak memiliki wewenang administrator untuk mengubah password sistem.'
    ]);
}

// 4. Validate input
$body = Response::getJsonBody();
$newPw = trim((string)($body['newPassword'] ?? ''));

if (empty($newPw) || strlen($newPw) < 6) {
    Response::json(400, [
        'success' => false,
        'code'    => 'INVALID_PASSWORD',
        'message' => 'Password baru wajib diisi dan minimal 6 karakter.'
    ]);
}

// 5. Generate secure Bcrypt hash
$pwHash = password_hash($newPw, PASSWORD_BCRYPT);

$dir = dirname(__DIR__) . '/data';
if (!is_dir($dir)) {
    @mkdir($dir, 0755, true);
}

$payload = [
    'username'     => 'admin',
    'passwordHash' => $pwHash,
    'updatedAt'    => date('Y-m-d H:i:s')
];

@file_put_contents($dir . '/admin-password.json', json_encode($payload, JSON_PRETTY_PRINT), LOCK_EX);

// 6. If admin row exists in MySQL guru table, update it as well for full synchronization
try {
    require_once __DIR__ . '/../lib/repositories/GuruRepository.php';
    $guruRepo = new GuruRepository();
    $existingAdmin = $guruRepo->findByUsername('admin');
    if ($existingAdmin) {
        $guruRepo->update('admin', ['password' => $pwHash]);
    }
} catch (Throwable $dbErr) {
    // Non-fatal if MySQL is sterile/empty
}

Response::json(200, [
    'success' => true,
    'message' => 'Password administrator berhasil diperbarui secara aman.'
]);
