<?php
//--------------------------------------------------------------------
//APlikasi Bank Mini Untuk Siswa SMK MVP ARS Internasional
//File ini untuk menampung semua fungsi yang digunakan di aplikasi
//Fungsi-fungsi yang ada di sini dapat digunakan untuk berbagai keperluan, seperti validasi input, manipulasi data, dan lain-lain.


//==============================================
//1. Fungsi Pengaturan Waktu
//==============================================

//Set timezone ke Asia/Jakarta
date_default_timezone_set('Asia/Jakarta');
$waktu_sekarang = date('Y-m-d H:i:s');

//===========================================
//2. fungsi untuk mengambil Data dari Database
//===========================================

//Karna menggunakan hp 8.2, kita bisa menggunakan mysqli dengan cara yang lebih aman dan efisien. Berikut adalah contoh fungsi untuk mengambil data dari database
//Menyiapkan variabel koneksi database
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "db_rpl2526";

//membuat koneksi
$koneksi = mysqli_connect($servername, $username, $password, $dbname);

//mengecek koneksi, apakah berhasil atau tidak. Jika tidak berhasil, maka akan menampilkan pesan error dan menghentikan eksekusi script.
//Jika berhasil, maka koneksi akan digunakan untuk query ke database di bagian lain dari aplikasi.
if (!$koneksi) {
    die("koneksi gagal: " . mysqli_connect_error());
}

//================================================
//3. fungsi Autonumber untuk ID User
//=================================================

function Autonumber($tabel, $kolom, $lebar = 0, $awalan = '')
{
    global $koneksi;

    $query = mysqli_query($koneksi, "SELECT $kolom FROM $tabel ORDER BY $kolom DESC LIMIT 1")
        or die('Error: ' . mysqli_error($koneksi));

    $jumlah_record = mysqli_num_rows($query);

    if ($jumlah_record == 0) {
        $nomor_baru = 1;
    } else {
        $row = mysqli_fetch_array($query);
        $nomor_baru = intval(substr($row[0], strlen($awalan))) + 1;
    }

    if ($lebar > 0) {
        $id_baru = $awalan . str_pad($nomor_baru, $lebar, "0", STR_PAD_LEFT);
    } else {
        $id_baru = $awalan . $nomor_baru;
    }
    return $id_baru;
}

//Penggunaan fungsi autonumber
//$id_user_baru = autonumber("tbl_users", "id_user", 7, "ADM"); \
// //Contoh penggunaan fungsi autonumber untuk tabel tbl_users, kolom id_user, lebar 5, dan awalan ADM


//=========================================================
//4. Fungsi Registrasi User
//=========================================================

function registrasi($data)
{
    global $koneksi, $waktu_sekarang;
    global $waktu_sekarang; //memanggil variable waktu_sekarang dari luar fungsi
    

    //1. mengambil data dari form dan wajib bersihkan data input untuk mencegah SQL Injection
    //stripslashes() digunakan untuk untuk menghapus backslashes dari input, dan strtolower() digunakan untuk mengubah email menjadi huruf kecil agar konsisten.
    //karena id_user kita buat automat, kita tidak perlu membersihkan input ini, tapi tetap kita lakukan untuk keamanan. tidak perlu menggunakan htmlspecialchars() karena kita tidak menampilkan data ini ke halaman web, tapi tetep bisa digunakan jika ingin menampilkan data ini di halaman web.


    $id_user = stripslashes($data["id_user"]);
    $email = strtolower(stripslashes($data["email"]));

    //form password dan confirm password kita kasih pengaman agar tidak ada yang bisa merubah query ke database, kita gunakan mysqli_real_escape_string() untuk membersihkan input password dari karakter-karakter yang berbahaya.
    $password = mysqli_real_escape_string($koneksi, $data["password"]);
    $confirm_password = mysqli_real_escape_string($koneksi, $data["confirm_password"]);

    //2. kita cek apakah email sudah terdaftar di database atau belum. Jika sudah  terdaftar, maka kita akan menampilkan pesan error dan menghentikan proses registrasi.
    $result = mysqli_query($koneksi, "SELECT email FROM tbl_users WHERE email = '$email'") or die('Error: ' . mysqli_error($koneksi));

    //jika hasil pencarian email sudah ada, maka kita akan menampilkan pesan error dan menghentikan proses registrasi.
    if (mysqli_fetch_assoc($result)) {
        echo "<script>
        alert('Waduh Email sudah terpakai nich!');
        </script>";
        return false; //menghentikan proses registrasi jika email sudah terdaftar
    }

    //3. kita cek apakah password dan confirm password sama. Jika tidak sama, maka kita akan menampilkan pesan error dan menghentikan proses registrasi.
    if ($password !== $confirm_password) {
        echo "<script>
        alert('waduh password dan confirm password tidak sama bosku! coba cek lagi ya!');
        document.location.href = 'register.php'; //mengarahkan kembali ke halaman registrasi
        </script>";
        return false; // menghentikan proses registrasi jika password dan confirm password tidak sama
    }

    //4. jika semua data sudah valid (cocok0), maka kita akan melakukan enkripsi password menggunakan password_hash() dengan algoritma default (BCRYPT)
    $password_hash = password_hash($password, PASSWORD_DEFAULT);

    //5. kita cek apakah ID Role "Admin" dan ambil ID (id_tipe_user) dari tabel tbl_tipe_user
    $sql = "SELECT * FROM tbl_tipe_user WHERE tipe_user = 'Admin'";
    $hasil_tipe_user = mysqli_query($koneksi, $sql) or die('Error: ' . mysqli_error($koneksi));
    $row_tipe_user = mysqli_fetch_assoc($hasil_tipe_user);
    $id = $row_tipe_user['id_tipe_user'];

    //6. jika semua data sudah valid, maka kita akan memasukkan data ke dalam tabel tbl_users di database.
    //simpan data ke tabel tbl_users di database
    $query = "INSERT INTO tbl_users SET
    id_user = '$id_user',
    email = '$email',
    password = '$password_hash',
    role = '$id',
    created_at = '$waktu_sekarang',
    updated_at ='$waktu_sekarang'";
    mysqli_query($koneksi, $query) or die('Gagal simpan data di tabel tbl_user: ' . mysqli_error($koneksi));

    //simpan data ke tabel tbl_admin di database
    $query2 = "INSERT INTO tbl_admin SET
    id_user = '$id_user',
    created_at = '$waktu_sekarang',
    updated_at ='$waktu_sekarang'";
    mysqli_query($koneksi, $query2) or die('Gagal simpan data di tabel tbl_admin: ' . mysqli_error($koneksi));

    //7. memberikan pesan sukses jika registrasi berhasil dan mengarahkan ke halaman login
    echo "<script>
    alert('Selamat! Registrasi berhasil. Silahkan login untuk melanjutkan.');
    document.location.href = 'login.php';// Mengarahkan ke halaman login
    </script>";

    // Mengembalikan nilai 
    return mysqli_affected_rows($koneksi); // Mengembalikan jumlah baris yang terpengaruh oleh query INSERT

}

//=========================================================
//5. Fungsi Tampil User
//=========================================================

function tampil($DATA)
{
    global $koneksi; //memanggil variabel koneksi dari luar fungsi

    //Query untuk mengambil semua data user dari tabel
    $query = mysqli_query($koneksi, $DATA) or die('Error: ' . mysqli_error($koneksi));

    //membuat array untuk menampung data user
    $data = []; // kita menyiapkan variabel yang isinya kosong untuk nanti kita akan gunakan
    while ($row = mysqli_fetch_assoc($query)) {
        $data[] = $row; // menambah setiap baris data ke dalam array
    }

    return $data; // mengembalikan nilai array data yang akan di tampilkan
}

//=========================================================
//6. Fungsi Upload File
// fungsi ini untuk mengupload file ke server dan mengembalikan nama file yang diupload. jika gagal, akan mengembalikan false.
//========================================================= 

function upload_files($file_input, $identifier, $target_folder = '', $option = [])
{

    //a. Setting Default untuk karakter file yang bisa di upload
    $default = [
        'max_size' => 2 * 1024 * 1024, // 2MB
        'allowed_types' => ['jpg', 'png', 'gif', 'bmp',],
        'create_folder' => true, // Jika folder tidak ada, maka aka dibuat otomatis
        'prefix' => ''           // Awalan nama file yang diupload, misal: Admin maka menjadi 'ADM'
    ];

    //menggabungkan opsi user dengan default
    $options = array_merge($default, $option);

    //b. Validasi input file yang diberikan 
// Cek apakah struktur file yang diupload sesuai dengan struktur file yang diharapkan
    if (!isset($file_input['error']) || !isset($file_input['tmp_name'])) {
        return [
            'success' => false,
            'message' => 'File yang di upload tidak valid. Pastikan form sudah diisi dengan benar (menggunakan enctype="multipart/form-data").'
        ];
    }

    //ambil informasi file yang diupload
    $errors = $file_input['error']; //kode error (0 = sukses, 4 = tidak ada file yang diupload, dll)
    $tmpName = $file_input['tmp_name']; //nama file sementara di server
    $namaAsli = $file_input['name']; //nama file asli di komputer user
    $ukuranFile = $file_input['size']; //ukuran file dalam byte

    //c. Cek apakah ada file yang diupload oleh user. Jika tidak ada, maka akan mengembalikan false.
    if ($errors === UPLOAD_ERR_NO_FILE) {
        return [
            'success' => false,
            'message' => 'Tidak ada file yang diupload. Silahkan pilih file terlebih dahulu.'
        ];
    }

    //d. Cek error  upload lainnya
    // UPLOAD_ERR_OK (0): Tidak ada error, file berhasil diupload.
    if ($errors !== UPLOAD_ERR_OK) {
        //Array untuk mapping kode error ke pesan error yang lebih dipahami
        $errorMessages = [
            UPLOAD_ERR_INI_SIZE => 'File yang diupload melebihi batas ukuran yang diizinkan oleh server (Upload_max_filesize). Silahkan hubungi administrator.',
            UPLOAD_ERR_FORM_SIZE => 'File yang diupload melebihi batas ukuran yang diizinkan oleh Form (MAX_FILE_SIZE). Silahkan hubungi administrator.',
            UPLOAD_ERR_PARTIAL => 'File hanya terupload sebagian. Silahkan coba lagi.',
            UPLOAD_ERR_NO_TMP_DIR => 'Folder sementara untuk upload tidak ditemukan. Silahkan hubungi administrator.',
            UPLOAD_ERR_CANT_WRITE => 'Gagal menulis file ke disk. Silahkan hubungi administrator.',
            UPLOAD_ERR_EXTENSION => 'Upload file dihentikan oleh ekstensi PHP. Silahkan hubungi administrator.'
        ];

        $message = isset($errorMessages[$errors]) ? $errorMessages[$errors] : 'Terjadi kesalahan saat mengupload file. Silahkan coba lagi.';
        return ['success' => false, 'message' => $message];

    }

    //e. Ambil ekstensi file dari nama file asli dan ubah menjadi huruf kecil
    $ekstensiFile = strtolower(pathinfo($namaAsli, PATHINFO_EXTENSION)); //contoh: jpg, png, gif

    //f. Cek apakah ekstensi file sesuai dengan yang diizinkan 
    if (!in_array($ekstensiFile, $options['allowed_types'])) {
        //buat daftar ekstensi yang diizinkan menjadi string (contoh: jpg, jpeg, png, gif, bmp)
        $ext_str = implode(', ', $options['allowed_types']);
        return [
            'success' => false,
            'message' => "Ekstensi file tidak diizinkan. Hanya file dengan ekstensi berikut yang diperbolehkan: $ext_str."
        ];
    }
    //g. Cek ukuran file, apakah melebihi batas maksimal yang diizinkan
    if ($ukuranFile > $options['max_size']) {
        //konversi byte ke MB untuk pesan error agar lebih mudah dibaca pengguna
        $max_size_mb = number_format($options['max_size'] / 1048576, 2); //1MB = 1048576 byte
        return [
            'success' => false,
            'message' => "Ukuran file melebihi batas maksimal yang diizinkan. Maksimal ukuran file adalah $max_size_mb MB."
        ];
    }
    //h. Membuat nama file baru untuk menghindari konflik nama file di server.
    //Agar menghindari nama file duplikat, menghindari karakter aneh (spasi, simbol, dll), dan agar lebih aman, agar lebih aman, Akan mempermudah dalam identifikasi gambar yang diupload.
    //format nama file: PREFIX_IDENIFIER_TIMESTAMP_UNIQUE.EXTENSION
    //contoh : ADM_admin123_20240615_123456_abcdef.jpg

    $prefix = $options['prefix'] ? $options['prefix'] . '_' : ''; // Jika prefix tidak kosong, tambahkan underscore

    //uniqid() digunakan untuk membuat string unik berdasarkan waktu saat ini dalam mikrodetik. Ini akan membantu menghindari nama file duplikat.
    $unique_id = uniqid(); //membuat string unik berdasarkan waktu saat ini  dalam mikro

    //mengambil timestamp saat ini 
    $timestamp = date('Ymd_His'); // format: YYYYMMDD_HHMMSS

    //Gabungkan semua bagian untuk membuat nama file baru
    $namaFileBaru = $prefix . $identifier . '_' . $timestamp . '_' . $unique_id . '.' . $ekstensiFile; // contoh: ADM_admin123_20240615_123456_abcdef.jpg

    //i. menentukan path folder tujuan upload file.
    $file_path = rtrim($target_folder, '/') . '/' . $namaFileBaru;

    //j. Pindahkan file yang di temp ke folder tujuan
    if (move_uploaded_file($tmpName, $file_path)) {
        //Jika upload berhasil/sukses, maka akan mengembalikan array dengan informasi file yang diupload 
        return [
            'success' => true,                    //Sukses mengupload file
            'message' => 'File berhasil upload.', //pesan sukses 
            'Filename_asli' => $namaAsli,         //Nama file asli yang diupload
            'Filename_tersimpan' => $namaFileBaru, //Nama baru file yang tersimpan di server
            'path' => $file_path,                   //path lengkap file yang tersimpan di server
            'size' => $ukuranFile,                  //ukuran file dalam byte
            'size_mb' => round($ukuranFile / 1048576, 2), //ukuran file dalam MB
            'extension' => $ekstensiFile,                //ekstensi file
            'identifier' => $identifier,                 //Identifier yang digunakan untuk membuat nama file baru
            'prefix' => $options['prefix']               //prefix yang digunakan untuk membuat nama filebaru
        ];
    } else {
        //jika gagal upload file, maka akan mengembalikan array dengan informasi error
        return [
            'success' => false,
            'message' => 'Gagal memindahkan file ke folder tujuan. silahkan coba lagi. pastikan folder tujuan memiliki izin tulis (write permission) yang cukup.',
        ];
    }
}

//=========================================================
//7. Fungsi Tambah User Admin
//=========================================================

function tambah_admin($DATA, $FILES, $target_folder = "../images/images_all")
{

    global $koneksi, $waktu_sekarang; // memanggil variabel koneksi dan waktu_sekarang dari luar fungsi

    //a. Bersihkan data yang di kirim dari form untuk mencegah SQL Injection
    $id_admin = htmlspecialchars(trim($DATA["id_admin"] ?? ''));
    $nama_admin = htmlspecialchars(trim($DATA["nama_admin"] ?? ''));
    $alamat_admin = htmlspecialchars(trim($DATA["alamat_admin"] ?? ''));
    $telepon_admin = htmlspecialchars(trim($DATA["telepon_admin"] ?? ''));
    $jenkel = htmlspecialchars(trim($DATA["jenkel"] ?? ''));
    $email = htmlspecialchars(trim($DATA["email"] ?? ''));
    $password = htmlspecialchars(trim($DATA["password"] ?? ''));
    $password2 = htmlspecialchars(trim($DATA["password2"] ?? ''));
    $role = htmlspecialchars(trim($DATA["role"] ?? ''));


    //b. Validasi apakah ada form yang kosong, jika ada maka akan menampilkan pesan error dan menghentikan proses tambah admin.\
    $errors = []; //menyiapkan array untuk menampung pesan error
    if (empty($id_admin))
        $errors[] = "ID Admin tidak boleh kosong.";
    if (empty($nama_admin))
        $errors[] = "Nama Admin tidak boleh kosong.";
    if (empty($alamat_admin))
        $errors[] = "Alamat Admin tidak boleh kosong.";
    if (empty($telepon_admin))
        $errors[] = "Telepon Admin tidak boleh kosong.";
    if (empty($jenkel))
        $errors[] = "Jenis Kelamin Admin tidak boleh kosong.";
    if (empty($email))
        $errors[] = "Email Admin tidak boleh kosong.";
    if (empty($password))
        $errors[] = "Password Admin tidak boleh kosong.";
    if (empty($password2))
        $errors[] = "Konfirmasi Password Admin tidak boleh kosong.";
    if (empty($role))
        $errors[] = "Role Admin tidak boleh kosong.";

    //jika ada form kosong, maka akan menampilkan pesan error dan menghentikan proses tambah admin.
    if (!empty($errors)) {
        $_SESSION['errors'] = $errors; //menyiapkan pesan error ke dalam session
        return false; // menghentikan proses tambah admin
    }

    //c. validasi pakai username/email sudah ada di database, jika sudah ada maka akan menampilkan pesan error dan menghentikan proses tambah admin.
    $result = mysqli_query($koneksi, "SELECT email FROM tbl_users WHERE email ='$email'") or die('Error: ' . mysqli_error($koneksi));
    if (mysqli_fetch_assoc($result)) {
        $_SESSION['errors'] = ["Email Admin yang di input sudah terdaftar."]; //Menyiapkan pesan error ke dalam session
        return false; // menghentikan proses tambah admin
    }

    //d. validasi apakah password dan konfirmasi password sama, jika tidak sama maka akan menampilkan pesan error dan menghentikan proses tambah admin.
    if ($password !== $password2) {
        $_SESSION['errors'] = ["Password dan Konfirmasi Password Admin tidak sama"]; //menyimpan pesan error ke dalam session
        return false; // menghentikan proses tambah admin
        }
        
        //e.validasi panjang password minimal 6 karakter, jika kurang dari 6 karakter maka akan menampilkan pesan error dan menghentikan proses tambah admin.
    if (strlen($password) < 6) {
        $_SESSION['errors'] = ["Password Admin minimal 6 karakter."]; // menyimpan pesan error ke dalam session
        return false; // menghentikan proses tambah admin
        }

    // f. proses upload file foto admin - menggunakan $target_folder untuk menentukan folder tujuan upload file foto admin. jika tidak ada file yang di upload, maka akan menampilkan pesan error dan menghentikan proses tambah admin.
    $gambar_foto = null; //Inisialisasi variabel gambar_photo
    if (isset($FILES['photo']) && $FILES['photo']['error'] !== UPLOAD_ERR_NO_FILE) {
        if ($FILES['photo']['error'] !== UPLOAD_ERR_OK) {
            $_SESSION['form_errors'] = ['Terjadi error upload file'];
            return false;
            }
            
            $upload_result = upload_files(
                $FILES['photo'],
                $id_admin,
                $target_folder,
                [
                'max_size' => 1048576,
                'allowed_types' => ['jpg', 'jpeg', 'png', 'bmp'],
                'create_folder' => true,
                'prefix' => 'ADM'
            ]
        );

        if ($upload_result['success']) {
            $gambar_foto = $upload_result['Filename_tersimpan'];
        } else {
            $_SESSION['form_errors'] = [$upload_result['message']];
            return false;
        }
        }
        
        //g.enkripsi password menggunakan password_hash() sebelum disimpan ke database
        $password_hash = password_hash($password, PASSWORD_DEFAULT);

    //h. Simpan data ke tabel tbl_users dan tbl_admin dalam satu transaksi
    mysqli_begin_transaction($koneksi);

    try {
        $sql_user = "INSERT INTO tbl_users SET
    id_user = '$id_admin',
    email = '$email',
    password = '$password_hash',
    role = (SELECT id_tipe_user FROM tbl_tipe_user WHERE tipe_user = 'Admin'),
    created_at = '$waktu_sekarang'";

        if (!mysqli_query($koneksi, $sql_user)) {
            throw new Exception("Gagal menambahkan user: " . mysqli_error($koneksi));
            }

        $sql_admin = "INSERT INTO tbl_admin SET 
nama_admin = '$nama_admin',
alamat_admin = '$alamat_admin',
telepon_admin = '$telepon_admin',
jenis_kelamin = '$jenkel',
path_photo_admin = " . ($gambar_foto ? "'$gambar_foto'" : "NULL") . ",
id_user = '$id_admin',
created_at = '$waktu_sekarang'";

if (!mysqli_query($koneksi, $sql_admin)) {
            throw new Exception("Gagal menambahkan admin: " . mysqli_error($koneksi));
            }
            
        mysqli_commit($koneksi);

        $_SESSION['success_message'] = "Data berhasil ditambahkan!";

        return true;
    } catch (Exception $e) {
        //jika ada error, rollback transaksi dan hapus file foto yang sudah diupload
        mysqli_rollback($koneksi);

        if (!empty($gambar_foto)) {
            $file_path = rtrim($target_folder, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $gambar_foto;
            if (file_exists($file_path)) {
                unlink($file_path);
            }
        }

        $_SESSION['form_errors'] = [$e->getMessage()];
        return false;
    }
    }

    //=========================================================
    //7. Fungsi edit admin 
    //untuk melakukan update data pengguna admin
    // - upload foto opsional (tidak wajib)
    // - jika upload foto baru maka, foto lama yang ada di folder harus di hapus
    // - jika tidak upload foto baru maka, foto yang lama tetap sama dengan yang di database
    //=========================================================

    function edit_admin($DATA, $FILES, $target_folder = '../images/user_admin')
    {
        global $koneksi;
        global $waktu_sekarang;

        //1. ambil data dari form (bersihkan )
        $id_admin = htmlspecialchars(trim($DATA['id_admin']));
        $nama_admin = htmlspecialchars(trim($DATA['nama_admin']));
        $alamat_admin = htmlspecialchars(trim($DATA['alamat_admin']));
        $telepon = htmlspecialchars(trim($DATA['telepon']));
        $jenkel = htmlspecialchars(trim($DATA['jenkel']));
        $email = htmlspecialchars(trim($DATA['email']));

        //2. validasi form kosong
        $errors = [];

        if (empty($id_admin)){
            $errors[]= "ID admin tidak boleh kosong";
        }
        if (empty($nama_admin)){
            $errors[]= "Nama admin tidak boleh kosong";
        }
        if (empty($alamat_admin)){
            $errors[]= "Alamat admin tidak boleh kosong";
        }
        if (empty($telepon)){
            $errors[]= "Telepon admin tidak boleh kosong";
        }
        if (empty($jenkel)){
            $errors[]= "Jenis kelamin tidak boleh kosong";
        }
        if (empty($email)){
            $errors[]= "Email tidak boleh kosong";
        }
        if (!empty($errors)){
            $_SESSION['form_errors']= $errors;
            return false;
        }

   //3. ambil data foto lama dari database (PERBAIKAN NAMA TABEL & VARIABEL)
    $query_foto = mysqli_query($koneksi, "SELECT path_photo_admin FROM tbl_admin WHERE id_user = '$id_admin'");
    $data_lama = mysqli_fetch_assoc($query_foto);
    $foto_lama = $data_lama['path_photo_admin'] ?? '';
    }
?>