<?php
/**
 * license-php/api/auth-profile.php
 * POST /api/user/change-password
 * POST /api/user/photo
 * GET  /api/user/profile
 * Authoritative Self-Service Credentials & Profile Persistence for Non-Admin Roles (Siswa, Guru, Tendik).
 * Single Source of Truth: presensi_client_db.
 */

require_once __DIR__ . '/../lib/Response.php';
require_once __DIR__ . '/../lib/LicenseCrypto.php';
require_once __DIR__ . '/../lib/repositories/SiswaRepository.php';
require_once __DIR__ . '/../lib/repositories/GuruRepository.php';
require_once __DIR__ . '/../lib/repositories/TendikRepository.php';

Response::handleCors();

$uri = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH);
$uri = rtrim(preg_replace('#^/license-php/router\.php#', '', $uri), '/');
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$body = Response::getJsonBody();

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

// 1. Mandatory JWT Authentication Gate
$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 diperlukan.'
    ]);
}

$payload = null;
if (file_exists($pubKeyPath)) {
    $pubKeyPem = file_get_contents($pubKeyPath);
    $verified = LicenseCrypto::verifyToken($token, $pubKeyPem);
    if ($verified['valid']) {
        $exp = $verified['payload']['exp'] ?? 0;
        if ($exp === 0 || $exp >= time()) {
            $payload = $verified['payload'];
        }
    }
}

if (!$payload) {
    Response::json(401, [
        'success' => false,
        'code'    => 'UNAUTHENTICATED',
        'message' => 'Akses ditolak: Sesi login tidak valid atau token kedaluwarsa.'
    ]);
}

// 2. Strict Role Authorization Gate: Only Siswa, Guru, and Tendik
$callerRole = strtolower(trim((string)($payload['role'] ?? '')));
$callerId   = trim((string)($payload['sub'] ?? ($payload['username'] ?? '')));

if (!in_array($callerRole, ['siswa', 'guru', 'tendik'], true)) {
    Response::json(403, [
        'success' => false,
        'code'    => 'FORBIDDEN_SELF_SERVICE_ROLE',
        'message' => 'Akses ditolak: Endpoint self-service profil ini hanya tersedia untuk Siswa, Guru, dan Tendik.'
    ]);
}

if (!$callerId) {
    Response::json(401, [
        'success' => false,
        'code'    => 'INVALID_IDENTITY',
        'message' => 'Identitas pengguna dalam token tidak valid.'
    ]);
}

// Instantiate Repositories
$siswaRepo = new SiswaRepository();
$guruRepo = new GuruRepository();
$tendikRepo = new TendikRepository();

// Helper: Resolve target user strictly from JWT identity
function resolveAuthUser(string $role, string $id, SiswaRepository $sr, GuruRepository $gr, TendikRepository $tr): ?array {
    $cleanId = strtolower(trim($id));
    if ($role === 'siswa') {
        return $sr->findByNisn($cleanId) ?: ($sr->findByBarcode($cleanId) ?: null);
    } elseif ($role === 'guru') {
        return $gr->findByUsername($cleanId) ?: ($gr->findByNip($cleanId) ?: ($gr->findByBarcode($cleanId) ?: null));
    } elseif ($role === 'tendik') {
        return $tr->findByUsername($cleanId) ?: ($tr->findByNip($cleanId) ?: ($tr->findByBarcode($cleanId) ?: null));
    }
    return null;
}

$user = resolveAuthUser($callerRole, $callerId, $siswaRepo, $guruRepo, $tendikRepo);
if (!$user) {
    Response::json(404, [
        'success' => false,
        'code'    => 'USER_NOT_FOUND',
        'message' => 'Akun pengguna tidak ditemukan di database.'
    ]);
}

// -----------------------------------------------------------------------------
// ROUTE 1: POST /api/user/change-password
// -----------------------------------------------------------------------------
if (strpos($uri, '/api/user/change-password') !== false) {
    if ($method !== 'POST') {
        Response::json(405, ['success' => false, 'message' => 'Method Not Allowed']);
    }

    $oldPassword = trim((string)($body['oldPassword'] ?? ($body['old_password'] ?? '')));
    $newPassword = trim((string)($body['newPassword'] ?? ($body['new_password'] ?? '')));

    if (!$oldPassword) {
        Response::json(400, [
            'success' => false,
            'code'    => 'MISSING_OLD_PASSWORD',
            'message' => 'Password saat ini wajib diisi.'
        ]);
    }

    if (!$newPassword || strlen($newPassword) < 4) {
        Response::json(400, [
            'success' => false,
            'code'    => 'INVALID_PASSWORD_POLICY',
            'message' => 'Password baru minimal harus terdiri dari 4 karakter.'
        ]);
    }

    // Verify old password
    $currentHash = $user['password'] ?? null;
    $isOldValid = false;

    if ($currentHash) {
        if (password_verify($oldPassword, $currentHash)) {
            $isOldValid = true;
        } elseif ($callerRole === 'siswa' && ($oldPassword === '12345' || $oldPassword === ($user['nisn'] ?? ''))) {
            // Student fallback verification
            $isOldValid = true;
        } elseif ($oldPassword === $currentHash) {
            // Legacy plaintext match
            $isOldValid = true;
        }
    } else {
        // Uninitialized password defaults to '12345' for Siswa
        if ($callerRole === 'siswa' && $oldPassword === '12345') {
            $isOldValid = true;
        }
    }

    if (!$isOldValid) {
        Response::json(401, [
            'success' => false,
            'code'    => 'INVALID_OLD_PASSWORD',
            'message' => 'Password saat ini tidak sesuai.'
        ]);
    }

    // Hash new password using authoritative Bcrypt with cost 12
    $newHash = password_hash($newPassword, PASSWORD_BCRYPT, ['cost' => 12]);

    $updated = false;
    if ($callerRole === 'siswa') {
        $updated = $siswaRepo->update($user['nisn'], ['password' => $newHash]);
    } elseif ($callerRole === 'guru') {
        $updated = $guruRepo->update($user['username'], ['password' => $newHash]);
    } elseif ($callerRole === 'tendik') {
        $updated = $tendikRepo->update($user['username'], ['password' => $newHash]);
    }

    if (!$updated) {
        Response::json(500, [
            'success' => false,
            'code'    => 'UPDATE_FAILED',
            'message' => 'Gagal menyimpan password baru ke database.'
        ]);
    }

    Response::json(200, [
        'success' => true,
        'code'    => 'PASSWORD_CHANGED',
        'message' => 'Password berhasil diperbarui.'
    ]);
}

// -----------------------------------------------------------------------------
// ROUTE 2: POST /api/user/photo
// -----------------------------------------------------------------------------
if (strpos($uri, '/api/user/photo') !== false) {
    if ($method !== 'POST') {
        Response::json(405, ['success' => false, 'message' => 'Method Not Allowed']);
    }

    $photoData = $body['foto'] ?? ($body['photo'] ?? null);

    if ($photoData !== null && $photoData !== '') {
        $photoStr = trim((string)$photoData);

        // Security check: Size limit (max 5MB)
        if (strlen($photoStr) > 6 * 1024 * 1024) {
            Response::json(400, [
                'success' => false,
                'code'    => 'FILE_TOO_LARGE',
                'message' => 'Ukuran foto melebihi batas maksimal (5MB).'
            ]);
        }

        // Security check: Image MIME validation
        $isValidImage = false;
        if (preg_match('#^data:image/(jpeg|jpg|png|webp|gif);base64,#i', $photoStr)) {
            $isValidImage = true;
        } else {
            // Validate decoded base64 image data
            $rawBin = @base64_decode($photoStr, true);
            if ($rawBin !== false && strlen($rawBin) > 10) {
                $finfo = new finfo(FILEINFO_MIME_TYPE);
                $mime = $finfo->buffer($rawBin);
                if (in_array($mime, ['image/jpeg', 'image/png', 'image/webp', 'image/gif'], true)) {
                    $isValidImage = true;
                    // Format into proper data URI
                    $photoStr = 'data:' . $mime . ';base64,' . base64_encode($rawBin);
                }
            }
        }

        if (!$isValidImage) {
            Response::json(400, [
                'success' => false,
                'code'    => 'INVALID_IMAGE_FORMAT',
                'message' => 'Format gambar tidak valid. Gunakan format JPG, PNG, atau WebP.'
            ]);
        }
    } else {
        $photoStr = null; // Clearing photo
    }

    $updated = false;
    if ($callerRole === 'siswa') {
        $updated = $siswaRepo->update($user['nisn'], ['foto' => $photoStr]);
    } elseif ($callerRole === 'guru') {
        $updated = $guruRepo->update($user['username'], ['foto' => $photoStr]);
    } elseif ($callerRole === 'tendik') {
        $updated = $tendikRepo->update($user['username'], ['foto' => $photoStr]);
    }

    if (!$updated) {
        Response::json(500, [
            'success' => false,
            'code'    => 'UPDATE_FAILED',
            'message' => 'Gagal memperbarui foto profil di database.'
        ]);
    }

    Response::json(200, [
        'success' => true,
        'code'    => 'PHOTO_UPDATED',
        'message' => 'Foto profil berhasil diperbarui.',
        'foto'    => $photoStr
    ]);
}

// -----------------------------------------------------------------------------
// ROUTE 3: GET /api/user/profile
// -----------------------------------------------------------------------------
if (strpos($uri, '/api/user/profile') !== false) {
    if ($method !== 'GET') {
        Response::json(405, ['success' => false, 'message' => 'Method Not Allowed']);
    }

    // Sanitize user profile output (exclude password hash)
    unset($user['password']);

    Response::json(200, [
        'success' => true,
        'data'    => array_merge($user, [
            'role' => $callerRole
        ])
    ]);
}

Response::json(404, ['success' => false, 'message' => 'Endpoint profil tidak ditemukan.']);
