<?php
// ============================================================
// core/helpers.php – Fungsi Pembantu Global
// ============================================================

require_once ROOT_PATH . '/config/config.php';
require_once ROOT_PATH . '/config/database.php';

// ---- AUTH -----------------------------------------------

function isLoggedIn(): bool {
    return isset($_SESSION['user_id']);
}

function requireLogin(): void {
    if (!isLoggedIn()) {
        header('Location: ' . BASE_URL . '/modules/auth/login.php');
        exit;
    }
}

function hasRole(string|array $roles): bool {
    if (!isLoggedIn()) return false;
    $r = is_array($roles) ? $roles : [$roles];
    return in_array($_SESSION['role'], $r);
}

function requireRole(string|array $roles): void {
    requireLogin();
    if (!hasRole($roles)) {
        $_SESSION['flash_error'] = 'Anda tidak memiliki akses ke halaman ini.';
        header('Location: ' . BASE_URL . '/modules/dashboard/index.php');
        exit;
    }
}

function isAdmin(): bool      { return hasRole('admin'); }
function isDinas(): bool      { return hasRole(['admin','dinas']); }
function isSekolah(): bool    { return hasRole('sekolah'); }

// ---- FLASH MESSAGE ------------------------------------

function setFlash(string $type, string $msg): void {
    $_SESSION["flash_{$type}"] = $msg;
}

function getFlash(string $type): string {
    $msg = $_SESSION["flash_{$type}"] ?? '';
    unset($_SESSION["flash_{$type}"]);
    return $msg;
}

// ---- SANITASI & VALIDASI ------------------------------

function e(string $str): string {
    return htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}

function sanitize(string $str): string {
    return trim(strip_tags($str));
}

function redirect(string $url): void {
    header("Location: {$url}");
    exit;
}

function csrf_token(): string {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

function csrf_verify(): bool {
    $token = $_POST['csrf_token'] ?? '';
    return hash_equals($_SESSION['csrf_token'] ?? '', $token);
}

function csrf_field(): string {
    return '<input type="hidden" name="csrf_token" value="' . e(csrf_token()) . '">';
}

// ---- FORMAT -------------------------------------------

function formatTanggal(string $date, string $format = 'd M Y'): string {
    if (empty($date)) return '-';
    $bulan = ['','Januari','Februari','Maret','April','Mei','Juni',
              'Juli','Agustus','September','Oktober','November','Desember'];
    $d = date_create($date);
    if (!$d) return '-';
    $out = date_format($d, $format);
    // Ganti nama bulan
    for ($i = 1; $i <= 12; $i++) {
        $out = str_replace(date('M', mktime(0,0,0,$i,1)), substr($bulan[$i],0,3), $out);
        $out = str_replace(date('F', mktime(0,0,0,$i,1)), $bulan[$i], $out);
    }
    return $out;
}

function formatBytes(int $bytes, int $precision = 2): string {
    $units = ['B','KB','MB','GB'];
    $pow   = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow   = min($pow, count($units) - 1);
    return round($bytes / (1024 ** $pow), $precision) . ' ' . $units[$pow];
}

// ---- PAGINATION ----------------------------------------

function paginate(string $sql, array $params, int $perPage, int $page): array {
    $countSql = "SELECT COUNT(*) FROM ({$sql}) AS _count";
    $total    = Database::count($countSql, $params);
    $pages    = (int) ceil($total / $perPage);
    $page     = max(1, min($page, max($pages, 1)));
    $offset   = ($page - 1) * $perPage;
    $data     = Database::fetchAll("{$sql} LIMIT {$perPage} OFFSET {$offset}", $params);
    return [
        'data'     => $data,
        'total'    => $total,
        'pages'    => $pages,
        'current'  => $page,
        'per_page' => $perPage,
    ];
}

function renderPagination(array $pag, string $baseUrl): string {
    if ($pag['pages'] <= 1) return '';
    $html = '<nav><ul class="pagination pagination-sm mb-0">';
    // Prev
    $prev = $pag['current'] > 1 ? $pag['current'] - 1 : 1;
    $dis  = $pag['current'] <= 1 ? ' disabled' : '';
    $html .= "<li class='page-item{$dis}'><a class='page-link' href='{$baseUrl}&page={$prev}'>‹</a></li>";
    // Pages
    $start = max(1, $pag['current'] - 2);
    $end   = min($pag['pages'], $pag['current'] + 2);
    for ($i = $start; $i <= $end; $i++) {
        $act  = $i === $pag['current'] ? ' active' : '';
        $html .= "<li class='page-item{$act}'><a class='page-link' href='{$baseUrl}&page={$i}'>{$i}</a></li>";
    }
    // Next
    $next = $pag['current'] < $pag['pages'] ? $pag['current'] + 1 : $pag['pages'];
    $dis  = $pag['current'] >= $pag['pages'] ? ' disabled' : '';
    $html .= "<li class='page-item{$dis}'><a class='page-link' href='{$baseUrl}&page={$next}'>›</a></li>";
    $html .= '</ul></nav>';
    return $html;
}

// ---- UPLOAD FILE --------------------------------------

function uploadFile(array $file, string $subdir, array $allowedTypes, int $maxSize): array {
    $result = ['success' => false, 'filename' => '', 'error' => ''];

    if ($file['error'] !== UPLOAD_ERR_OK) {
        $result['error'] = 'Upload error: ' . $file['error'];
        return $result;
    }
    if ($file['size'] > $maxSize) {
        $result['error'] = 'Ukuran file melebihi batas ' . formatBytes($maxSize);
        return $result;
    }

    // Verifikasi MIME (bukan hanya ekstensi)
    $finfo    = new finfo(FILEINFO_MIME_TYPE);
    $mimeType = $finfo->file($file['tmp_name']);
    if (!in_array($mimeType, $allowedTypes)) {
        $result['error'] = 'Tipe file tidak diizinkan.';
        return $result;
    }

    $ext      = pathinfo($file['name'], PATHINFO_EXTENSION);
    $filename = date('YmdHis') . '_' . bin2hex(random_bytes(8)) . '.' . strtolower($ext);
    $destDir  = UPLOAD_PATH . '/' . $subdir;

    if (!is_dir($destDir)) {
        mkdir($destDir, 0755, true);
    }

    if (move_uploaded_file($file['tmp_name'], $destDir . '/' . $filename)) {
        $result['success']  = true;
        $result['filename'] = $filename;
    } else {
        $result['error'] = 'Gagal menyimpan file.';
    }
    return $result;
}

function deleteFile(string $subdir, string $filename): void {
    $path = UPLOAD_PATH . '/' . $subdir . '/' . $filename;
    if (file_exists($path)) {
        unlink($path);
    }
}

// ---- AUDIT LOG ----------------------------------------

function auditLog(string $aksi, ?string $tabel = null, ?int $recordId = null, ?string $desk = null): void {
    if (!isLoggedIn()) return;
    Database::execute(
        "INSERT INTO audit_log (user_id,aksi,tabel,record_id,deskripsi,ip_address)
         VALUES (?,?,?,?,?,?)",
        [$_SESSION['user_id'], $aksi, $tabel, $recordId, $desk, $_SERVER['REMOTE_ADDR'] ?? null]
    );
}
