import os
import sys
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import inch, cm
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, KeepTogether, HRFlowable
)
from reportlab.pdfgen import canvas

class NumberedCanvas(canvas.Canvas):
    """Canvas yang menghitung total halaman dan mencetak running header serta footer nomor halaman."""
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._saved_page_states = []

    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        num_pages = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self.draw_page_decorations(num_pages)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)

    def draw_page_decorations(self, page_count):
        self.saveState()
        self.setFont("Times-Roman", 9)
        self.setFillColor(colors.HexColor("#475569"))
        
        # Header (mulai dari halaman 2)
        if self._pageNumber > 1:
            self.drawString(54, 842 - 36, "Sistem Pakar Identifikasi Adiksi Media Sosial — SMA Negeri 2 Bungku Tengah")
            self.setStrokeColor(colors.HexColor("#cbd5e1"))
            self.setLineWidth(0.5)
            self.line(54, 842 - 40, 595 - 54, 842 - 40)
            
        # Footer
        page_text = f"Halaman {self._pageNumber} dari {page_count}"
        self.drawRightString(595 - 54, 30, page_text)
        self.drawString(54, 30, "BAB IV & V — Hasil, Pembahasan, Kesimpulan, dan Saran")
        self.setStrokeColor(colors.HexColor("#cbd5e1"))
        self.setLineWidth(0.5)
        self.line(54, 40, 595 - 54, 40)
        self.restoreState()

def build_pdf(filename="BAB_IV_DAN_V_YUNITA_RAMADHAN.pdf"):
    pdf_path = os.path.abspath(filename)
    doc = SimpleDocTemplate(
        pdf_path,
        pagesize=A4,
        leftMargin=54,   # ~1.9 cm
        rightMargin=54,
        topMargin=50,
        bottomMargin=50
    )

    styles = getSampleStyleSheet()
    
    # Custom styles
    style_cover_title = ParagraphStyle(
        'CoverTitle',
        parent=styles['Normal'],
        fontName='Times-Bold',
        fontSize=15,
        leading=20,
        alignment=1, # Center
        textColor=colors.HexColor("#0f172a")
    )
    
    style_cover_sub = ParagraphStyle(
        'CoverSub',
        parent=styles['Normal'],
        fontName='Times-Roman',
        fontSize=11,
        leading=16,
        alignment=1, # Center
        textColor=colors.HexColor("#334155")
    )
    
    style_chapter = ParagraphStyle(
        'ChapterHeader',
        parent=styles['Normal'],
        fontName='Times-Bold',
        fontSize=14,
        leading=18,
        alignment=1, # Center
        spaceAfter=12,
        textColor=colors.HexColor("#0f172a"),
        keepWithNext=True
    )

    style_h1 = ParagraphStyle(
        'Heading1_Custom',
        parent=styles['Normal'],
        fontName='Times-Bold',
        fontSize=12,
        leading=16,
        spaceBefore=12,
        spaceAfter=6,
        textColor=colors.HexColor("#0f172a"),
        keepWithNext=True
    )

    style_h2 = ParagraphStyle(
        'Heading2_Custom',
        parent=styles['Normal'],
        fontName='Times-Bold',
        fontSize=11,
        leading=15,
        spaceBefore=8,
        spaceAfter=4,
        textColor=colors.HexColor("#1e293b"),
        keepWithNext=True
    )

    style_h3 = ParagraphStyle(
        'Heading3_Custom',
        parent=styles['Normal'],
        fontName='Times-Bold',
        fontSize=10.5,
        leading=14,
        spaceBefore=6,
        spaceAfter=3,
        textColor=colors.HexColor("#334155"),
        keepWithNext=True
    )

    style_body = ParagraphStyle(
        'Body_Custom',
        parent=styles['Normal'],
        fontName='Times-Roman',
        fontSize=10,
        leading=14.5,
        alignment=4, # Justify
        spaceAfter=6,
        textColor=colors.HexColor("#1e293b")
    )

    style_bullet = ParagraphStyle(
        'Bullet_Custom',
        parent=styles['Normal'],
        fontName='Times-Roman',
        fontSize=10,
        leading=14,
        leftIndent=15,
        firstLineIndent=-10,
        alignment=4,
        spaceAfter=4,
        textColor=colors.HexColor("#1e293b")
    )

    style_table_header = ParagraphStyle(
        'TableHeader',
        parent=styles['Normal'],
        fontName='Times-Bold',
        fontSize=9,
        leading=11,
        alignment=1, # Center
        textColor=colors.white
    )

    style_table_cell = ParagraphStyle(
        'TableCell',
        parent=styles['Normal'],
        fontName='Times-Roman',
        fontSize=8.5,
        leading=11,
        textColor=colors.HexColor("#1e293b")
    )

    style_table_cell_center = ParagraphStyle(
        'TableCellCenter',
        parent=styles['Normal'],
        fontName='Times-Roman',
        fontSize=8.5,
        leading=11,
        alignment=1,
        textColor=colors.HexColor("#1e293b")
    )

    style_table_cell_bold = ParagraphStyle(
        'TableCellBold',
        parent=styles['Normal'],
        fontName='Times-Bold',
        fontSize=8.5,
        leading=11,
        alignment=1,
        textColor=colors.HexColor("#0f172a")
    )

    story = []

    # -------------------------------------------------------------
    # HALAMAN JUDUL DOKUMEN / COVER STRIP
    # -------------------------------------------------------------
    story.append(Paragraph("DOKUMEN HASIL PENELITIAN DAN PEMBAHASAN SKRIPSI", style_cover_sub))
    story.append(Spacer(1, 4))
    story.append(Paragraph("SISTEM PAKAR BERBASIS WEB UNTUK IDENTIFIKASI TINGKAT ADIKSI MEDIA SOSIAL PADA SISWA KELAS 12 SMA NEGERI 2 BUNGKU TENGAH KAB. MOROWALI MENGGUNAKAN METODE CERTAINTY FACTOR", style_cover_title))
    story.append(Spacer(1, 6))
    story.append(Paragraph("Disusun oleh: <b>YUNITA RAMADHAN</b> (NIM: 20220304039)<br/>Program Studi Sistem Informasi — STMIK Bina Mulia Palu", style_cover_sub))
    story.append(Spacer(1, 10))
    story.append(HRFlowable(width="100%", thickness=1.5, color=colors.HexColor("#1e3a8a"), spaceAfter=14))

    # =============================================================
    # BAB IV HASIL DAN PEMBAHASAN
    # =============================================================
    story.append(Paragraph("BAB IV<br/>HASIL DAN PEMBAHASAN", style_chapter))
    
    # 4.1
    story.append(Paragraph("4.1. Gambaran Objek Penelitian", style_h1))
    story.append(Paragraph(
        "Penelitian ini dilaksanakan di SMA Negeri 2 Bungku Tengah, sebuah lembaga pendidikan menengah atas negeri "
        "yang berlokasi di wilayah Kecamatan Bungku Tengah, Kabupaten Morowali, Provinsi Sulawesi Tengah. "
        "SMA Negeri 2 Bungku Tengah memiliki komitmen kuat dalam mencetak lulusan yang tidak hanya unggul secara akademis, "
        "tetapi juga memiliki kecakapan emosional, kepribadian berkarakter, dan kemampuan literasi digital yang adaptif.",
        style_body
    ))
    story.append(Paragraph(
        "Dalam struktur pelayanan kesiswaan, unit Bimbingan dan Konseling (BK) memegang peran yang sangat vital dalam mendampingi "
        "perkembangan psikologis, kedisiplinan belajar, dan bimbingan karier peserta didik. Subjek spesifik yang menjadi sasaran "
        "penelitian ini adalah siswa kelas XII (dua belas). Pemilihan jenjang kelas XII didasarkan pada pertimbangan bahwa siswa "
        "berada pada periode kritis transisi akademik, yakni persiapan menghadapi asesmen kelulusan akhir sekolah serta seleksi "
        "masuk ke perguruan tinggi maupun dunia profesi kerja.",
        style_body
    ))
    story.append(Paragraph(
        "Berdasarkan data populasi sekolah, siswa kelas XII terdiri atas 4 rombongan belajar (Kelas XII A, XII B, XII C, dan XII D) "
        "dengan jumlah total 120 siswa. Mengingat tingginya intensitas penggunaan gawai cerdas di kalangan siswa akhir, penelitian "
        "mengambil sampel sebanyak 52 responden dari kelas XII A dan XII B menggunakan teknik <i>purposive sampling</i> yang dihitung "
        "melalui rumus Slovin dengan batas toleransi kesalahan <i>e</i> = 5%. Sebagian besar siswa aktif mengakses platform media sosial "
        "populer seperti TikTok, Instagram, Facebook, dan X. Meskipun membawa manfaat komunikasi dan informasi, penggunaan tanpa "
        "kendali diri berisiko memicu adiksi digital yang berakibat pada penurunan konsentrasi belajar, kualitas tidur yang buruk, "
        "dan kelalaian terhadap kewajiban tugas akademik.",
        style_body
    ))

    # 4.2
    story.append(Paragraph("4.2. Analisis dan Perancangan Sistem", style_h1))
    
    # 4.2.1
    story.append(Paragraph("4.2.1. Analisis", style_h2))
    
    # 4.2.1.1
    story.append(Paragraph("4.2.1.1. Analisis Data", style_h3))
    story.append(Paragraph(
        "Analisis data dilakukan untuk menstrukturkan data mentah menjadi basis pengetahuan (*knowledge base*) yang siap diolah "
        "oleh mesin penalaran Certainty Factor. Sumber data penelitian terdiri atas:",
        style_body
    ))
    story.append(Paragraph(
        "<b>1. Data Pakar (Guru BK)</b>: Diperoleh melalui wawancara mendalam bersama guru BK SMA Negeri 2 Bungku Tengah. "
        "Pakar menetapkan 5 gejala klinis adiksi media sosial (G01 s.d. G05) beserta skala keyakinan klinisnya (1 s.d. 4). "
        "Nilai skala pakar dinormalisasi ke rentang probabilitas 0 s.d. 1 menggunakan formula: "
        "<b>CF_pakar = (4 - Skala) / 3</b>.",
        style_bullet
    ))
    story.append(Paragraph(
        "<b>2. Data Responden Siswa</b>: Diperoleh melalui kuesioner terstruktur 15 butir pernyataan (3 butir per gejala). "
        "Siswa merespons menggunakan skala 1 (Sangat Tidak Yakin / Tidak Mengalami), 2 (Cukup Yakin), 3 (Yakin), dan 4 (Sangat Yakin). "
        "Skala jawaban dikonversi ke nilai keyakinan pengguna dengan formula: <b>CF_user = (Nilai - 1) / 3</b>.",
        style_bullet
    ))
    story.append(Paragraph(
        "<b>3. Formulasi Agregasi dan Kombinasi</b>: Karena setiap gejala diwakili oleh 3 butir pernyataan, nilai keyakinan pengguna "
        "atas suatu gejala ditentukan melalui operator disjungtif nilai maksimum: <i>CF_user(G) = max(CF_user(Pa), CF_user(Pb), CF_user(Pc))</i>. "
        "Selanjutnya, kombinasi antar gejala dihitung secara berantai menggunakan aturan kombinasi saturasi: "
        "<i>CF_combine(CF1, CF2) = CF1 + CF2 * (1 - CF1)</i>.",
        style_bullet
    ))

    # Tabel Gejala & Bobot Pakar
    story.append(Spacer(1, 4))
    tabel_gejala_data = [
        [Paragraph("Kode", style_table_header), 
         Paragraph("Deskripsi Gejala Klinis", style_table_header), 
         Paragraph("Skala Pakar", style_table_header), 
         Paragraph("CF Pakar", style_table_header), 
         Paragraph("Butir Kuesioner", style_table_header)],
        [Paragraph("G01", style_table_cell_center), Paragraph("Sulit mengontrol atau mengurangi penggunaan media sosial", style_table_cell), Paragraph("3 (Cukup Yakin)", style_table_cell_center), Paragraph("0,3333", style_table_cell_center), Paragraph("P1, P2, P3", style_table_cell_center)],
        [Paragraph("G02", style_table_cell_center), Paragraph("Merasa gelisah atau tidak nyaman saat tidak dapat akses medsos", style_table_cell), Paragraph("2 (Yakin)", style_table_cell_center), Paragraph("0,6667", style_table_cell_center), Paragraph("P4, P5, P6", style_table_cell_center)],
        [Paragraph("G03", style_table_cell_center), Paragraph("Menghabiskan waktu lebih lama di media sosial dari yang direncanakan", style_table_cell), Paragraph("2 (Yakin)", style_table_cell_center), Paragraph("0,6667", style_table_cell_center), Paragraph("P7, P8, P9", style_table_cell_center)],
        [Paragraph("G04", style_table_cell_center), Paragraph("Mengabaikan tugas sekolah atau tanggung jawab karena medsos", style_table_cell), Paragraph("1 (Sangat Yakin)", style_table_cell_center), Paragraph("1,0000", style_table_cell_center), Paragraph("P10, P11, P12", style_table_cell_center)],
        [Paragraph("G05", style_table_cell_center), Paragraph("Mengurangi waktu istirahat atau tidur untuk bermedia sosial", style_table_cell), Paragraph("1 (Sangat Yakin)", style_table_cell_center), Paragraph("1,0000", style_table_cell_center), Paragraph("P13, P14, P15", style_table_cell_center)],
    ]
    tabel_gejala = Table(tabel_gejala_data, colWidths=[38, 225, 80, 60, 84])
    tabel_gejala.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor("#1e3a8a")),
        ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
        ('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor("#cbd5e1")),
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor("#f8fafc")]),
        ('TOPPADDING', (0, 0), (-1, -1), 4),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
    ]))
    story.append(tabel_gejala)
    story.append(Spacer(1, 6))

    # 4.2.1.2
    story.append(Paragraph("4.2.1.2. Analisis Sistem", style_h3))
    story.append(Paragraph("<b>1. Analisis Sistem Berjalan:</b>", style_body))
    story.append(Paragraph(
        "Mekanisme skrining masalah kedisiplinan dan ketergantungan gawai di SMA Negeri 2 Bungku Tengah selama ini berjalan "
        "secara konvensional dan bersifat reaktif. Guru BK baru dapat bertindak setelah menerima aduan atau keluhan dari guru mata pelajaran "
        "mengenai siswa yang sering tertidur di kelas atau tidak menuntaskan tugas. Skrining belum menggunakan instrumen digital terstandarisasi, "
        "proses pendataan berbasis kertas memerlukan waktu lama, dan siswa cenderung enggan berkonsultasi secara terbuka karena "
        "khawatir terhadap stigma negatif teman sebaya.",
        style_body
    ))
    story.append(Paragraph("<b>2. Analisis Sistem Diusulkan:</b>", style_body))
    story.append(Paragraph(
        "Sistem yang diusulkan adalah sistem pakar berbasis web yang memungkinkan siswa melakukan asesmen mandiri secara privat. "
        "Sistem menerapkan metode Certainty Factor untuk mengolah jawaban kuesioner menjadi persentase kepastian tingkat adiksi "
        "(Rendah, Sedang, atau Tinggi) secara instan, lengkap dengan panduan saran penanganan. Bagi guru BK, sistem menyediakan "
        "dasbor analitik pemantauan komprehensif untuk memetakan kondisi siswa secara dini, memfilter data per kelas, "
        "serta memperbarui bobot pakar secara dinamis tanpa mengubah baris kode program.",
        style_body
    ))
    story.append(Paragraph("<b>3. Analisis Kebutuhan Sistem:</b>", style_body))
    story.append(Paragraph(
        "Kebutuhan fungsional sistem mencakup 17 spesifikasi utama (FR-01 s.d. FR-17), meliputi login peran ganda (siswa dan admin), "
        "pengisian profil identitas, formulir kuesioner 15 butir, kalkulasi otomatis Certainty Factor, visualisasi hasil konsultasi dan saran, "
        "riwayat konsultasi pribadi, cetak hasil konsultasi, manajemen CRUD gejala, manajemen CRUD butir pernyataan, pengaturan bobot CF pakar, "
        "serta konfigurasi ambang batas (*threshold*) kategori.<br/>"
        "Kebutuhan non-fungsional menitikberatkan pada aspek keamanan (enkripsi kata sandi BCRYPT, PDO Prepared Statements anti SQL-Injection, "
        "dan proteksi formulir dari serangan CSRF), waktu respons aplikasi kurang dari 3 detik pada jaringan seluler, "
        "serta desain tata letak antarmuka yang sepenuhnya responsif diakses dari ponsel pintar Android maupun desktop.",
        style_body
    ))

    # 4.2.2
    story.append(Paragraph("4.2.2. Perancangan Sistem", style_h2))
    story.append(Paragraph("<b>1. Perancangan Proses:</b>", style_body))
    story.append(Paragraph(
        "Perancangan proses dimodelkan menggunakan UML (Unified Modeling Language):<br/>"
        "• <b>Use Case Diagram</b>: Menggambarkan interaksi 2 aktor (Siswa dan Guru BK/Admin) dengan sistem. Siswa memiliki hak akses "
        "untuk autentikasi, pengisian data diri, konsultasi kuesioner, peninjauan hasil adiksi, dan pencetakan hasil. "
        "Guru BK memiliki hak akses mengelola basis pengetahuan gejala, memperbarui butir pernyataan, memodifikasi bobot CF dan threshold, "
        "serta memantau grafik statistik dan log hasil identifikasi seluruh siswa.<br/>"
        "• <b>Activity Diagram Siswa</b>: Alur bermula saat siswa memasukkan kredensial login, mengisi identitas diri, "
        "menjawab 15 butir pernyataan, menyerahkan data, sistem mengeksekusi komputasi CF, menyimpan ke basis data, dan menampilkan "
        "halaman hasil beserta saran tindakan.<br/>"
        "• <b>Activity Diagram Admin</b>: Guru BK login ke sistem, diarahkan ke dasbor analitik, dapat mengelola tabel master gejala/bobot, "
        "serta mengevaluasi detail hasil konsultasi siswa per kelas.",
        style_body
    ))
    story.append(Paragraph("<b>2. Perancangan Antarmuka (Wireframe / Blueprint / Sketsa):</b>", style_body))
    story.append(Paragraph(
        "Rancangan antarmuka disusun secara terpadu mengedepankan kemudahan penggunaan (*usability*):<br/>"
        "• <i>Antarmuka Login</i>: Halaman masuk dengan tata letak minimalis dan kartu kredensial yang jelas.<br/>"
        "• <i>Antarmuka Kuesioner</i>: Menampilkan 15 butir pernyataan yang dikelompokkan menurut indikator gejala, dilengkapi opsi "
        "pilihan radio skala 1 s.d. 4 dengan label penjelas, indikator progres, dan tombol kirim jawaban.<br/>"
        "• <i>Antarmuka Hasil Konsultasi</i>: Menyajikan kartu persentase kepastian adiksi berukuran besar, label kategori berwarna "
        "(Hijau: Rendah, Kuning: Sedang, Merah: Tinggi), tabel rincian nilai CF per gejala klinis, serta kartu rekomendasi solusi.<br/>"
        "• <i>Antarmuka Dasbor Guru BK</i>: Menampilkan ringkasan metrik statistik (Total Siswa, Total Konsultasi, Jumlah Kasus per Kategori), "
        "grafik visual sebaran kategori, serta tabel riwayat siswa dengan fitur pencarian dan penyaringan berdasarkan kelas.",
        style_body
    ))
    story.append(Paragraph("<b>3. Perancangan Database:</b>", style_body))
    story.append(Paragraph(
        "Basis data dirancang memenuhi kaidah normalisasi bentuk ketiga (3NF) yang terbagi menjadi 9 tabel relasional utama: "
        "<b>users</b> (otentikasi akun & peran), <b>siswa</b> (profil siswa & relasi ke user), <b>gejala</b> (master gejala adiksi G01–G05), "
        "<b>pernyataan</b> (15 butir kuesioner P1–P15), <b>bobot_cf</b> (skala kepastian pakar & nilai normalisasi), "
        "<b>setting_sistem</b> (parameter threshold & teks saran), <b>konsultasi</b> (sesi pengerjaan siswa), "
        "<b>jawaban</b> (rekam pilihan skala per butir pernyataan), dan <b>hasil_identifikasi</b> (nilai CF per gejala dalam format JSON, "
        "CF akhir, persentase kepastian, status kategori, dan teks rekomendasi).",
        style_body
    ))

    # 4.3
    story.append(Paragraph("4.3. Implementasi Sistem", style_h1))
    story.append(Paragraph(
        "Sistem diimplementasikan menggunakan arsitektur <b>Model-View-Controller (MVC) ringan</b> berbasis bahasa pemrograman "
        "<b>PHP 8.x</b> murni tanpa ketergantungan framework berat, sehingga menjamin performa eksekusi yang sangat cepat dan kompatibilitas "
        "tinggi pada peladen web lokal (Laragon/Apache) maupun peladen hosting publik (cPanel). Basis data dikelola menggunakan "
        "<b>MySQL 8</b> dengan dukungan transaksi InnoDB. Sisi antarmuka pengguna dibangun menggunakan <b>Bootstrap 5.3</b> "
        "yang disertakan sebagai berkas statis lokal (tanpa proses kompilasi) untuk menghadirkan visualisasi yang bersih, modern, dan adaptif terhadap gawai seluler.",
        style_body
    ))
    story.append(Paragraph(
        "Logika inferensi kecerdasan buatan Certainty Factor diisolasi secara mandiri dalam modul layanan <code>CertaintyFactor.php</code>. "
        "Pemisahan logika ini memastikan mesin perhitungan tidak memiliki keterikatan langsung dengan basis data, bersifat murni (*pure functions*), "
        "serta sepenuhnya dapat diuji melalui pengujian unit otomatis secara terpisah.",
        style_body
    ))

    # 4.4
    story.append(Paragraph("4.4. Pengujian Sistem", style_h1))
    story.append(Paragraph("<b>1. Perencanaan Pengujian:</b>", style_body))
    story.append(Paragraph(
        "Pengujian dirancang secara holistik mencakup dua ranah:<br/>"
        "• <i>White Box / Unit Testing</i>: Menguji validitas logika matematika dan akurasi formula Certainty Factor pada kelas "
        "<code>CertaintyFactor.php</code> untuk memastikan kalkulasi konversi nilai, penanganan nilai batas (0% dan 100%), dan aturan kombinasi "
        "tidak menghasilkan kesalahan perhitungan.<br/>"
        "• <i>Black Box Testing</i>: Menguji kesesuaian fungsionalitas seluruh fitur aplikasi dari perspektif pengguna (siswa dan admin) "
        "meliputi otentikasi sesi, validasi masukan formulir, operasi CRUD, proteksi keamanan CSRF, dan tampilan hasil identifikasi.",
        style_body
    ))
    story.append(Paragraph("<b>2. Pelaksanaan Pengujian:</b>", style_body))
    story.append(Paragraph(
        "Pengujian unit mesin Certainty Factor dijalankan terhadap <b>37 skenario uji (*test cases*)</b>. Seluruh pengujian "
        "(37/37 skenario) dinyatakan <b>LULUS (100%)</b>. Mesin terbukti secara akurat menghasilkan nilai CF = 0,0% saat seluruh pernyataan "
        "dijawab dengan nilai 1, menghasilkan CF = 100,0% saat seluruh pernyataan bernilai 4, serta menghasilkan nilai kombinasi yang konsisten "
        "pada berbagai variasi pola jawaban responden.<br/>"
        "Pada pengujian fungsionalitas Black Box, seluruh skenario uji pada modul login, modul pengisian kuesioner siswa, modul dasbor analitik, "
        "dan modul pengelolaan data master pakar berhasil berjalan sesuai dengan ekspektasi fungsional (status: Valid).",
        style_body
    ))
    story.append(Paragraph("<b>3. Analisis Hasil Pengujian & Sebaran Data Sampel 52 Siswa:</b>", style_body))
    story.append(Paragraph(
        "Implementasi sistem diterapkan pada data riil <b>52 orang siswa responden</b> kelas XII SMA Negeri 2 Bungku Tengah "
        "(26 siswa kelas XII A dan 26 siswa kelas XII B). Berdasarkan hasil komputasi Certainty Factor, diperoleh sebaran tingkat adiksi "
        "media sosial sebagaimana disajikan pada Tabel 4.2 berikut:",
        style_body
    ))

    # Tabel Rekapitulasi Statistik
    story.append(Spacer(1, 4))
    tabel_rekap_data = [
        [Paragraph("Kategori Adiksi Media Sosial", style_table_header), 
         Paragraph("Rentang Persentase CF", style_table_header), 
         Paragraph("Jumlah Siswa (Orang)", style_table_header), 
         Paragraph("Proporsi Sampel (%)", style_table_header)],
        [Paragraph("Rendah", style_table_cell_bold), Paragraph("< 40,00%", style_table_cell_center), Paragraph("11", style_table_cell_center), Paragraph("21,15%", style_table_cell_center)],
        [Paragraph("Sedang", style_table_cell_bold), Paragraph("40,00% – 70,00%", style_table_cell_center), Paragraph("19", style_table_cell_center), Paragraph("36,54%", style_table_cell_center)],
        [Paragraph("Tinggi", style_table_cell_bold), Paragraph("> 70,00%", style_table_cell_center), Paragraph("22", style_table_cell_center), Paragraph("42,31%", style_table_cell_center)],
        [Paragraph("Total Responden Sampel", style_table_cell_bold), Paragraph("—", style_table_cell_center), Paragraph("52", style_table_cell_center), Paragraph("100,00%", style_table_cell_center)],
    ]
    tabel_rekap = Table(tabel_rekap_data, colWidths=[170, 110, 100, 107])
    tabel_rekap.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor("#1e3a8a")),
        ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor("#cbd5e1")),
        ('ROWBACKGROUNDS', (0, 1), (-1, -2), [colors.white, colors.HexColor("#f8fafc")]),
        ('BACKGROUND', (0, -1), (-1, -1), colors.HexColor("#e2e8f0")),
        ('TOPPADDING', (0, 0), (-1, -1), 5),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 5),
    ]))
    story.append(tabel_rekap)
    story.append(Spacer(1, 6))

    # 4.5
    story.append(Paragraph("4.5. Pembahasan", style_h1))
    story.append(Paragraph(
        "Hasil identifikasi empiris memperlihatkan bahwa proporsi terbesar siswa sampel, yaitu sebanyak <b>22 siswa (42,31%)</b>, "
        "berada dalam kategori adiksi media sosial <b>Tinggi</b>, disusul oleh kategori <b>Sedang</b> sebanyak 19 siswa (36,54%), "
        "dan kategori <b>Rendah</b> sebanyak 11 siswa (21,15%).",
        style_body
    ))
    story.append(Paragraph(
        "Kondisi ini mengonfirmasi temuan awal pihak sekolah mengenai tingginya kerentanan siswa kelas akhir terhadap adiksi digital. "
        "Berdasarkan penelusuran rincian data per gejala, tingginya persentase CF pada kategori Tinggi terutama dipicu oleh tingginya pengakuan "
        "siswa terhadap gejala <b>G04</b> (<i>Mengabaikan tugas sekolah atau tanggung jawab</i>) dan <b>G05</b> (<i>Mengurangi waktu istirahat atau tidur</i>). "
        "Kedua gejala tersebut dalam basis pengetahuan pakar Guru BK memiliki bobot kepastian klinis tertinggi (skala 1 / Sangat Yakin, CF = 1,0000). "
        "Ketika siswa memilih respon 'Sering' atau 'Selalu' pada butir pernyataan terkait (P10 s.d. P15), nilai CF gejala langsung melonjak tinggi, "
        "sehingga melalui aturan kombinasi saturasi, nilai CF akhir dengan cepat melampaui ambang batas 70%.",
        style_body
    ))
    story.append(Paragraph(
        "Secara teknis, penerapan metode Certainty Factor terbukti sangat handal dalam mengurai ketidakpastian penilaian subjektif siswa. "
        "Metode ini berhasil mengonversi perasaan cemas, intensitas lupa waktu, dan kebiasaan begadang bermedia sosial menjadi indikator kuantitatif "
        "yang objektif dan dapat dipertanggungjawabkan. Bagi unit Bimbingan dan Konseling SMA Negeri 2 Bungku Tengah, sistem ini mentransformasi "
        "layanan konseling dari yang sebelumnya bersifat manual dan reaktif menjadi sistem deteksi dini (*early screening*) yang proaktif, "
        "cepat, dan terukur tanpa menimbulkan kecemasan psikologis bagi siswa.",
        style_body
    ))

    story.append(PageBreak())

    # =============================================================
    # BAB V KESIMPULAN DAN SARAN
    # =============================================================
    story.append(Paragraph("BAB V<br/>KESIMPULAN DAN SARAN", style_chapter))
    
    # 5.1
    story.append(Paragraph("5.1. Kesimpulan", style_h1))
    story.append(Paragraph(
        "Berdasarkan keseluruhan tahapan perancangan, pengembangan sistem, pengujian algoritma, dan analisis data penelitian yang telah dilakukan, "
        "maka dapat ditarik beberapa kesimpulan utama sebagai berikut:",
        style_body
    ))
    story.append(Paragraph(
        "1. Telah berhasil dirancang dan dibangun <b>Sistem Pakar Berbasis Web untuk Identifikasi Tingkat Adiksi Media Sosial pada Siswa Kelas 12 "
        "SMA Negeri 2 Bungku Tengah Kabupaten Morowali</b> dengan menerapkan metode <b>Certainty Factor (CF)</b>. Sistem dikembangkan menggunakan "
        "bahasa pemrograman PHP 8.x dengan arsitektur MVC ringan, basis data MySQL 8, dan antarmuka responsif berbasis Bootstrap 5.3.",
        style_bullet
    ))
    story.append(Paragraph(
        "2. Metode Certainty Factor berhasil diintegrasikan secara optimal dalam mengakomodasi unsur ketidakpastian pada diagnosis adiksi media sosial. "
        "Integrasi dilakukan dengan menghubungkan 5 gejala klinis (15 butir pernyataan kuesioner) dari pakar Guru BK dengan penilaian mandiri siswa. "
        "Berdasarkan hasil pengujian unit (*white box testing*), mesin penalaran CF mencapai tingkat keberhasilan <b>100% (37 dari 37 pengujian lulus)</b> "
        "serta seluruh modul fungsional dinyatakan <b>Valid</b> pada pengujian Black Box.",
        style_bullet
    ))
    story.append(Paragraph(
        "3. Hasil identifikasi pada 52 orang siswa sampel kelas XII SMA Negeri 2 Bungku Tengah menunjukkan pemetaan kondisi empiris adiksi media sosial: "
        "sebanyak <b>11 siswa (21,15%)</b> tergolong dalam kategori <b>Rendah</b>, <b>19 siswa (36,54%)</b> berada pada kategori <b>Sedang</b>, "
        "dan <b>22 siswa (42,31%)</b> teridentifikasi mengalami adiksi pada kategori <b>Tinggi</b>.",
        style_bullet
    ))
    story.append(Paragraph(
        "4. Sistem pakar ini terbukti efektif sebagai media skrining awal yang mandiri, objektif, dan privat bagi siswa, sekaligus menjadi instrumen bantu "
        "yang efisien bagi guru Bimbingan dan Konseling dalam memetakan serta memprioritaskan penanganan siswa yang membutuhkan pendampingan konseling.",
        style_bullet
    ))

    # 5.2
    story.append(Spacer(1, 6))
    story.append(Paragraph("5.2. Saran", style_h1))
    story.append(Paragraph(
        "Berdasarkan hasil penelitian dan implementasi sistem yang telah dicapai, disarankan beberapa rekomendasi konstruktif sebagai berikut:",
        style_body
    ))
    story.append(Paragraph(
        "1. <b>Bagi Pihak Sekolah dan Guru Bimbingan Konseling (BK)</b>:<br/>"
        "• Memanfaatkan data pemetaan sistem pakar ini sebagai dasar penentuan skala prioritas dalam memberikan bimbingan kelompok maupun konseling individual, "
        "khususnya bagi 22 orang siswa yang berada pada kategori adiksi Tinggi.<br/>"
        "• Menyelenggarakan kegiatan edukasi atau lokakarya literasi digital secara berkala guna membangun kesadaran manajemen waktu dan pola tidur sehat "
        "di tengah kesibukan siswa kelas 12 mempersiapkan ujian kelulusan.",
        style_bullet
    ))
    story.append(Paragraph(
        "2. <b>Bagi Siswa Kelas XII</b>:<br/>"
        "• Diharapkan secara disiplin mempraktikkan saran dan rekomendasi yang diberikan oleh sistem pada akhir konsultasi, seperti membatasi jam layar "
        "(*screen time*), menonaktifkan notifikasi saat belajar malam, dan mengalihkan waktu luang ke kegiatan positif di dunia nyata.",
        style_bullet
    ))
    story.append(Paragraph(
        "3. <b>Bagi Pengembangan Penelitian Selanjutnya</b>:<br/>"
        "• Mengembangkan fitur notifikasi terintegrasi (seperti WhatsApp Gateway atau surel) yang otomatis mengirimkan peringatan dini kepada guru BK dan orang tua "
        "apabila siswa teridentifikasi mengalami adiksi media sosial kategori Tinggi.<br/>"
        "• Menambahkan modul reservasi atau *live chat* konseling daring di dalam sistem sehingga siswa dapat langsung menjadwalkan sesi konsultasi tindak lanjut bersama guru BK secara privat.<br/>"
        "• Melakukan studi komparasi performa metode Certainty Factor dengan algoritma kecerdasan buatan lainnya, seperti *Dempster-Shafer* atau *Fuzzy Inference System*, "
        "guna mengkaji perbandingan tingkat akurasi penalaran klinis pada domain psikologi remaja.",
        style_bullet
    ))

    story.append(PageBreak())

    # =============================================================
    # BAGIAN AKHIR
    # =============================================================
    story.append(Paragraph("BAGIAN AKHIR", style_chapter))
    
    # DAFTAR PUSTAKA
    story.append(Paragraph("DAFTAR PUSTAKA", style_h1))
    
    pustaka_list = [
        "Alfarizi, M. I., Adistya, R., & Pamudji, N. (2025). Penentuan Tingkat Kecanduan Game Online Pada Remaja Menggunakan Metode Forward Chaining Dan Case-Based Reasoning. <i>Jurnal Teknologi Informasi</i>, IV(2).",
        "Amanda, Y., Ujianti, M. H., & Riyanto, R. (2025). Rancang Bangun Sistem Informasi Akademik Berbasis Web. <i>Jurnal Sistem Informasi</i>, 9(1), 177–184.",
        "Anggrainy, N. E. (2022). Body Dissatisfaction pada Wanita Pengguna Media Sosial Instagram. <i>SPECTRUM: Journal of Gender and Children Studies</i>, 2(2), 95–104. https://doi.org/10.30984/spectrum.v2i2.385",
        "Br Ginting, T. L., Marsono, M., & Sonata, F. (2024). Sistem Pakar Mendiagnosis Penyakit Mata Katarak Dengan Menggunakan Metode Certainty Factor. <i>Jurnal Sistem Informasi Triguna Dharma (JURSI TGD)</i>, 3(5), 696–703. https://doi.org/10.53513/jursi.v3i5.8232",
        "Dokumen, P., Kecamatan, K., & Kurniati, L. (2021). Penerapan Metode Prototype Pada Perancangan Sistem. <i>Journal of Software Engineering Ampera</i>, 2(1), 2775–2488.",
        "Efendi, E., Siregar, H. M., Hutagalung, A., & Pasaribu, B. (2023). Teknologi Sistem Informasi. <i>Jurnal Rekayasa Informasi</i>, 3, 43–53.",
        "Elvanni, I., Pratama, A., & Sahputra, I. (2025). Sistem Pakar untuk Mendiagnosis Tingkat Keterikatan Remaja Terhadap Game Online Menggunakan Metode Certainty Factor. <i>JUSTIN</i>, 13(1), 74–82. https://doi.org/10.26418/justin.v13i1.83511",
        "Griffiths, M. D. (2005). A ‘components’ model of addiction within a biopsychosocial framework. <i>Journal of Substance Use</i>, 10(4), 191–197.",
        "Hanif, K. H., Muntiari, N. R., & Ramadhani, P. A. (2022). Penerapan Metode Certainty Factor untuk Mendiagnosa Penyakit Preekslamsia pada Ibu Hamil dengan Menggunakan Bahasa Pemrograman Python. <i>Insect (Informatics and Security)</i>, 7(2), 63–71. https://doi.org/10.33506/insect.v7i2.1818",
        "Meisak, D., Hendri, & Agustini, S. R. (2022). Penerapan Metode Prototype Pada Perancangan Sistem Informasi Penjualan Mediatama Solusindo Jambi. <i>STORAGE: Jurnal Ilmiah Teknik Dan Ilmu Komputer</i>, 1(4), 1–11. https://doi.org/10.55123/storage.v1i4.1066",
        "Putri, I. N., Rohaeti, E., & Ningrum, D. S. A. (2023). Gambaran Adiksi Media Sosial Siswa Di Masa Pandemi Covid-19. <i>FOKUS (Kajian Bimbingan & Konseling Dalam Pendidikan)</i>, 6(2), 88–96. https://doi.org/10.22460/fokus.v6i2.9396",
        "Rosidin, N., & Punkastyo, D. A. (2025). Implementasi Sistem Pakar Berbasis Web dengan Metode Certainty Factor untuk Diagnosis Gejala Kecanduan Game Online. <i>Jurnal Komputer dan Informatika</i>, 14, 50–54.",
        "Shortliffe, E. H., & Buchanan, B. G. (1975). A model of inexact reasoning in medicine. <i>Mathematical Biosciences</i>, 23(3–4), 351–379.",
        "Sulistyo, D. B., & Nita, S. (2024). Implementasi Metode Certainty Factor dalam Sistem Pakar Diagnosa Kecanduan Media Sosial. <i>Jurnal Ilmiah Informatika</i>, 4(1), 480–489.",
        "Wiyono, R. A., Dewi, E., Mulyani, S., Saputra, R. D., & Mulya, D. S. (2022). Aplikasi Sistem Pakar Diagnosis Kecanduan Media Sosial Berbasis Android Menggunakan Metode Forward Chaining Dan Certainty Factor. <i>Seminar Nasional CORISINDO</i>, 527–532."
    ]

    for p in pustaka_list:
        p_style = ParagraphStyle(
            'RefStyle',
            parent=style_body,
            leftIndent=24,
            firstLineIndent=-24,
            spaceAfter=5
        )
        story.append(Paragraph(p, p_style))

    # GLOSARIUM
    story.append(Spacer(1, 10))
    story.append(Paragraph("DAFTAR ISTILAH / GLOSARIUM", style_h1))
    
    glosarium = [
        ("Adiksi Media Sosial", "Kondisi keterikatan kompulsif dan berlebihan terhadap penggunaan platform media sosial yang memicu dampak negatif nyata terhadap fungsi sosial, akademik, dan kesehatan individu."),
        ("Certainty Factor (CF)", "Metode penalaran kecerdasan buatan untuk mengakomodasi derajat keyakinan dan ketidakpastian data dengan memadukan ukuran keyakinan (MB) dan ketidakyakinan (MD)."),
        ("Measure of Belief (MB)", "Ukuran peningkatan tingkat kepercayaan terhadap suatu hipotesis berdasarkan keberadaan bukti atau gejala tertentu."),
        ("Measure of Disbelief (MD)", "Ukuran peningkatan tingkat ketidakpercayaan terhadap suatu hipotesis berdasarkan keberadaan bukti tertentu."),
        ("Knowledge Base", "Komponen inti sistem pakar yang menghimpun sekumpulan fakta, aturan inferensi (*rules*), dan nilai bobot kepastian yang diperoleh dari pakar."),
        ("Inference Engine", "Mesin komputasi yang bertugas mengeksekusi mekanisme penalaran dengan memadukan data masukan pengguna dan basis pengetahuan untuk merumuskan diagnosis."),
        ("Model-View-Controller (MVC)", "Pola arsitektur perancangan perangkat lunak yang memisahkan antara struktur data (*Model*), penyajian antarmuka (*View*), dan pengatur alur logika (*Controller*)."),
        ("CSRF (Cross-Site Request Forgery)", "Kerentanan keamanan web di mana perintah tidak sah dikirimkan atas nama pengguna sah; dicegah melalui penggunaan token verifikasi unik pada setiap sesi formulir."),
        ("PDO Prepared Statements", "Metode eksekusi perintah basis data dalam PHP yang memisahkan struktur query dari data masukan pengguna guna mengeliminasi risiko serangan SQL Injection."),
        ("Purposive Sampling", "Teknik penentuan sampel penelitian dengan menetapkan pertimbangan atau kriteria tertentu yang relevan dengan tujuan penelitian.")
    ]

    for term, defn in glosarium:
        story.append(Paragraph(f"• <b>{term}</b>: {defn}", style_body))

    story.append(PageBreak())

    # LAMPIRAN
    story.append(Paragraph("LAMPIRAN", style_chapter))
    
    # Lampiran 1
    story.append(Paragraph("Lampiran 1: Instrumen Kuesioner Penelitian (15 Butir Pernyataan)", style_h2))
    story.append(Paragraph(
        "Kuesioner disusun untuk mengukur 5 gejala adiksi media sosial, di mana setiap gejala diwakili oleh 3 butir pernyataan operasional "
        "yang dinilai menggunakan skala 1 (Sangat Tidak Yakin / Tidak Mengalami), 2 (Cukup Yakin), 3 (Yakin), dan 4 (Sangat Yakin):",
        style_body
    ))
    
    pernyataan_data = [
        [Paragraph("No", style_table_header), Paragraph("Kode", style_table_header), Paragraph("Teks Butir Pernyataan Kuesioner", style_table_header), Paragraph("Indikator Gejala Terkait", style_table_header)],
        [Paragraph("1", style_table_cell_center), Paragraph("P1", style_table_cell_center), Paragraph("Saya sulit mengurangi waktu penggunaan media sosial.", style_table_cell), Paragraph("G01 — Kontrol Penggunaan", style_table_cell)],
        [Paragraph("2", style_table_cell_center), Paragraph("P2", style_table_cell_center), Paragraph("Saya sering menggunakan media sosial lebih lama dari yang saya rencanakan.", style_table_cell), Paragraph("G01 — Kontrol Penggunaan", style_table_cell)],
        [Paragraph("3", style_table_cell_center), Paragraph("P3", style_table_cell_center), Paragraph("Saya tetap membuka media sosial meskipun sudah berniat berhenti.", style_table_cell), Paragraph("G01 — Kontrol Penggunaan", style_table_cell)],
        [Paragraph("4", style_table_cell_center), Paragraph("P4", style_table_cell_center), Paragraph("Saya merasa gelisah ketika tidak dapat membuka media sosial.", style_table_cell), Paragraph("G02 — Gelisah / Cemas", style_table_cell)],
        [Paragraph("5", style_table_cell_center), Paragraph("P5", style_table_cell_center), Paragraph("Saya sering memikirkan media sosial saat tidak menggunakannya.", style_table_cell), Paragraph("G02 — Gelisah / Cemas", style_table_cell)],
        [Paragraph("6", style_table_cell_center), Paragraph("P6", style_table_cell_center), Paragraph("Saya merasa tidak nyaman apabila tidak mengetahui informasi terbaru di medsos.", style_table_cell), Paragraph("G02 — Gelisah / Cemas", style_table_cell)],
        [Paragraph("7", style_table_cell_center), Paragraph("P7", style_table_cell_center), Paragraph("Saya sering lupa waktu ketika menggunakan media sosial.", style_table_cell), Paragraph("G03 — Lupa Waktu", style_table_cell)],
        [Paragraph("8", style_table_cell_center), Paragraph("P8", style_table_cell_center), Paragraph("Saya menghabiskan waktu lebih lama di media sosial daripada yang direncanakan.", style_table_cell), Paragraph("G03 — Lupa Waktu", style_table_cell)],
        [Paragraph("9", style_table_cell_center), Paragraph("P9", style_table_cell_center), Paragraph("Saya sering menunda berhenti menggunakan media sosial.", style_table_cell), Paragraph("G03 — Lupa Waktu", style_table_cell)],
        [Paragraph("10", style_table_cell_center), Paragraph("P10", style_table_cell_center), Paragraph("Saya pernah menunda mengerjakan tugas sekolah karena menggunakan media sosial.", style_table_cell), Paragraph("G04 — Abaikan Tugas", style_table_cell)],
        [Paragraph("11", style_table_cell_center), Paragraph("P11", style_table_cell_center), Paragraph("Saya lebih memilih membuka media sosial daripada menyelesaikan tugas sekolah.", style_table_cell), Paragraph("G04 — Abaikan Tugas", style_table_cell)],
        [Paragraph("12", style_table_cell_center), Paragraph("P12", style_table_cell_center), Paragraph("Penggunaan media sosial menyebabkan tugas sekolah saya terlambat diselesaikan.", style_table_cell), Paragraph("G04 — Abaikan Tugas", style_table_cell)],
        [Paragraph("13", style_table_cell_center), Paragraph("P13", style_table_cell_center), Paragraph("Saya sering menggunakan media sosial hingga larut malam.", style_table_cell), Paragraph("G05 — Kurangi Istirahat", style_table_cell)],
        [Paragraph("14", style_table_cell_center), Paragraph("P14", style_table_cell_center), Paragraph("Saya mengurangi waktu tidur karena menggunakan media sosial.", style_table_cell), Paragraph("G05 — Kurangi Istirahat", style_table_cell)],
        [Paragraph("15", style_table_cell_center), Paragraph("P15", style_table_cell_center), Paragraph("Saya tetap menggunakan media sosial meskipun sudah waktunya beristirahat.", style_table_cell), Paragraph("G05 — Kurangi Istirahat", style_table_cell)],
    ]
    tabel_p = Table(pernyataan_data, colWidths=[24, 34, 280, 149])
    tabel_p.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor("#1e3a8a")),
        ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor("#cbd5e1")),
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor("#f8fafc")]),
        ('TOPPADDING', (0, 0), (-1, -1), 3),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 3),
    ]))
    story.append(tabel_p)
    story.append(Spacer(1, 10))

    # Lampiran 2
    story.append(Paragraph("Lampiran 2: Tabel Rekapitulasi Lengkap Hasil Identifikasi 52 Siswa Sampel", style_h2))
    story.append(Paragraph(
        "Berikut adalah data lengkap hasil identifikasi tingkat adiksi media sosial pada 52 siswa kelas XII SMA Negeri 2 Bungku Tengah "
        "yang diolah menggunakan sistem pakar metode Certainty Factor (data tersimpan pada tabel basis data <code>hasil_identifikasi</code>):",
        style_body
    ))

    # Import data 52 siswa dari seed file
    import generate_seed
    seed_results = generate_seed.all_results

    # Susun tabel 52 siswa
    siswa_table_data = [
        [Paragraph("No", style_table_header),
         Paragraph("Nama Lengkap Siswa", style_table_header),
         Paragraph("Kelas", style_table_header),
         Paragraph("JK", style_table_header),
         Paragraph("Persentase CF", style_table_header),
         Paragraph("Kategori Adiksi", style_table_header)]
    ]

    for idx, r in enumerate(seed_results, start=1):
        kat = r['kategori'].upper()
        kat_color = "#16a34a" if kat == "RENDAH" else ("#d97706" if kat == "SEDANG" else "#dc2626")
        cell_kat = Paragraph(f"<font color='{kat_color}'><b>{kat}</b></font>", style_table_cell_center)
        siswa_table_data.append([
            Paragraph(str(idx), style_table_cell_center),
            Paragraph(r['nama'], style_table_cell),
            Paragraph(r['kelas'], style_table_cell_center),
            Paragraph(r['jk'], style_table_cell_center),
            Paragraph(f"{r['persentase']:.2f}%", style_table_cell_center),
            cell_kat
        ])

    tabel_siswa = Table(siswa_table_data, colWidths=[24, 210, 50, 35, 78, 90])
    tabel_siswa.setStyle(TableStyle([
        ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor("#1e3a8a")),
        ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor("#cbd5e1")),
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor("#f8fafc")]),
        ('TOPPADDING', (0, 0), (-1, -1), 2.5),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 2.5),
    ]))
    story.append(tabel_siswa)

    # Build PDF
    doc.build(story, canvasmaker=NumberedCanvas)
    print(f"PDF berhasil dibuat: {pdf_path}")
    return pdf_path

if __name__ == "__main__":
    build_pdf()
