from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from pathlib import Path
from datetime import datetime

DOCX_PATH = Path(r'C:\xampp\htdocs\audit\dokumentasi\Dokumentasi_Sistem_Dashboard_Audit_MAINPP.docx')
EXPANDED_PATH = Path(r'C:\xampp\htdocs\audit\dokumentasi\Dokumentasi_Sistem_Dashboard_Audit_MAINPP_Lengkap.docx')
BLUE = RGBColor(15, 76, 129)
GREEN = RGBColor(15, 118, 110)
MUTED = RGBColor(100,116,139)

def shade_cell(cell, fill):
    tcPr=cell._tc.get_or_add_tcPr(); shd=OxmlElement('w:shd'); shd.set(qn('w:fill'), fill); tcPr.append(shd)

def cell_text(cell,text,bold=False,color=None):
    cell.text=''; p=cell.paragraphs[0]; r=p.add_run(str(text)); r.bold=bold; r.font.name='Arial'; r.font.size=Pt(9.5)
    if color: r.font.color.rgb=color
    cell.vertical_alignment=WD_CELL_VERTICAL_ALIGNMENT.CENTER

def style_table(tbl):
    tbl.alignment=WD_TABLE_ALIGNMENT.LEFT; tbl.style='Table Grid'
    for i,row in enumerate(tbl.rows):
        for cell in row.cells:
            if i==0: shade_cell(cell,'F8FBFF')
            for p in cell.paragraphs:
                for r in p.runs:
                    r.font.name='Arial'; r.font.size=Pt(9.5)
                    if i==0: r.bold=True; r.font.color.rgb=BLUE

def heading(doc,text,level=1):
    p=doc.add_heading(text,level)
    for r in p.runs: r.font.name='Arial'; r.font.color.rgb=BLUE if level<=2 else RGBColor(15,23,42)

def bullet(doc,text):
    p=doc.add_paragraph(style='List Bullet'); p.add_run(text)

def num(doc,text):
    p=doc.add_paragraph(style='List Number'); p.add_run(text)

def add_table(doc, headers, rows):
    tbl=doc.add_table(rows=1, cols=len(headers))
    for i,h in enumerate(headers): cell_text(tbl.cell(0,i),h,True,BLUE)
    for row in rows:
        cells=tbl.add_row().cells
        for i,v in enumerate(row): cell_text(cells[i],v,bold=(i==0 and len(headers)<=3))
    style_table(tbl)
    doc.add_paragraph()
    return tbl

doc=Document(str(DOCX_PATH))

doc.add_page_break()
heading(doc,'13. Objektif Sistem',1)
doc.add_paragraph('Objektif utama Dashboard Audit MAINPP adalah untuk menyediakan satu platform berpusat yang memudahkan proses pengurusan audit, pemantauan tindakan bahagian dan rekod transaksi pengguna secara lebih sistematik.')
for item in [
    'Mengurangkan kebergantungan kepada rekod manual atau fail berasingan.',
    'Memastikan tugasan audit boleh dijejaki mengikut bahagian/unit yang bertanggungjawab.',
    'Mempercepat proses semakan maklum balas dan catatan audit oleh Admin Audit.',
    'Meningkatkan kawalan capaian melalui permission berdasarkan bahagian dan pengguna individu.',
    'Menyediakan laporan ringkas melalui dashboard, carta dan bilangan isu selesai/belum selesai.',
    'Mewujudkan jejak audit melalui transaksi log pengguna.',
]: bullet(doc,item)

heading(doc,'14. Skop Sistem',1)
add_table(doc,['Skop','Termasuk','Tidak Termasuk / Cadangan Masa Hadapan'],[
    ('Pengurusan Audit','Daftar audit, kemaskini audit, tugasan bahagian, lampiran dan senarai audit.','Integrasi terus dengan sistem pengurusan dokumen rasmi.'),
    ('Maklum Balas Bahagian','Isi ringkasan, maklum balas, lampiran dan kemaskini dalam tempoh audit.','Workflow kelulusan bertingkat lebih daripada satu peringkat.'),
    ('Catatan Audit','Admin Audit memberi catatan kepada maklum balas bahagian.','E-signature atau pengesahan digital rasmi.'),
    ('Capaian Pengguna','CRUD dan rollback mengikut bahagian serta override pengguna individu.','Integrasi SSO/LDAP/Active Directory.'),
    ('Notifikasi','Notifikasi tugasan audit dan catatan audit dalam sistem.','Push notification mobile atau WhatsApp rasmi.'),
    ('Reset Kata Laluan','SMTP email dengan kod verifikasi.','MFA/OTP aplikasi authenticator.'),
])

heading(doc,'15. Spesifikasi Modul Terperinci',1)
module_details=[
('Dashboard','Memaparkan kad statistik, carta palang isu mengikut bahagian, carta pai status isu dan carta bar isu belum selesai. Untuk pengguna biasa, statistik difokuskan kepada bahagian sendiri.'),
('Daftar Maklumat Audit','Merekod perkara audit, tarikh mula, tarikh akhir, ringkasan audit, lampiran fail dan tindakan bahagian/unit. Sistem menghantar notifikasi kepada bahagian yang ditugaskan.'),
('Senarai Maklumat Audit','Menyediakan filter berdasarkan perkara, bahagian/unit, tempoh audit, status tindakan dan tarikh. Menyokong view, edit dan delete bergantung kepada capaian.'),
('Maklum Balas Audit','Bahagian yang ditugaskan boleh mengisi ringkasan, maklum balas dan lampiran. Sistem menghalang input sebelum tarikh mula dan selepas tarikh akhir.'),
('Detail Maklum Balas Audit','Admin Audit boleh melihat detail maklum balas dan memberi catatan audit. Edit/delete telah dibuang daripada detail mengikut keperluan semasa.'),
('Capaian Bahagian','Pentadbir Sistem menetapkan permission modul kepada semua pengguna dalam bahagian yang dipilih.'),
('Capaian Pengguna','Pentadbir Sistem menetapkan permission individu yang boleh override permission bahagian.'),
('Profile Pengguna','Pengguna boleh mengemaskini nama, emel, bahagian/unit dan kata laluan.'),
]
add_table(doc,['Modul','Spesifikasi'],module_details)

heading(doc,'16. SOP Operasi Harian',1)
heading(doc,'16.1 SOP Admin Audit',2)
for step in ['Login sebagai Admin Audit.','Daftar maklumat audit dan pilih tindakan bahagian.','Semak senarai maklum balas audit yang diterima.','Buka detail maklum balas untuk menyemak ringkasan, lampiran dan maklum balas.','Masukkan catatan audit jika perlu pembetulan atau pengesahan.','Tukar kelulusan audit bahagian kepada Selesai Audit apabila tindakan lengkap.','Pantau bilangan isu belum selesai dan selesai di dashboard.']: num(doc,step)
heading(doc,'16.2 SOP Pengguna Bahagian',2)
for step in ['Login sebagai Pengguna Biasa.','Semak dashboard untuk melihat audit yang ditugaskan kepada bahagian.','Buka audit yang memerlukan maklum balas.','Isi ringkasan, maklum balas dan lampiran dalam tempoh audit.','Kemaskini maklum balas jika menerima catatan audit daripada Admin Audit.','Pantau status sehingga audit disahkan selesai.']: num(doc,step)
heading(doc,'16.3 SOP Pentadbir Sistem',2)
for step in ['Semak pendaftaran pengguna baharu dan aktifkan akaun yang sah.','Tetapkan capaian bahagian mengikut modul dan action.','Tetapkan capaian individu jika terdapat pengecualian khas.','Semak transaksi log pengguna secara berkala.','Urus role dan status akaun pengguna, kecuali perlindungan role Pentadbir Sistem.','Semak backup database dan folder uploads.']: num(doc,step)

heading(doc,'17. Jadual Permission Modul',1)
add_table(doc,['Modul','Create','Read','Update','Delete','Rollback','Catatan'],[
('Senarai Maklum Balas Audit','Ya','Ya','Ya','Ya','Ya','Kawalan kepada senarai, detail dan catatan audit.'),
('Senarai Maklumat Audit','Ya','Ya','Ya','Ya','Ya','Termasuk daftar, edit, view dan padam maklumat audit.'),
('Daftar Pengguna','Ya','Ya','Tidak','Tidak','Tidak','Hanya create dan read sesuai untuk borang daftar pengguna.'),
('Pengurusan Pendaftaran','Tidak','Ya','Ya','Tidak','Tidak','Kelulusan atau penolakan akaun pengguna baharu.'),
('Senarai Pengguna','Ya','Ya','Ya','Ya','Ya','Pengurusan role dan status akaun bergantung capaian.'),
('Transaksi Log Pengguna','Ya','Ya','Ya','Ya','Ya','Biasanya read sahaja diberi kepada pihak tertentu.'),
])

heading(doc,'18. Kamus Data Ringkas',1)
heading(doc,'18.1 users',2)
add_table(doc,['Field','Jenis','Keterangan'],[
('id','INT UNSIGNED PK','ID unik pengguna.'),('nama','VARCHAR(150)','Nama penuh pengguna.'),('ic','VARCHAR(20)','Nombor kad pengenalan unik.'),('emel','VARCHAR(150)','Emel unik untuk login dan reset password.'),('role','ENUM','Pengguna Biasa, Admin Audit atau Pentadbir Sistem.'),('jabatan','VARCHAR(150)','Bahagian/unit pengguna.'),('approval_status','ENUM','pending, active atau rejected.'),('account_status','ENUM','active atau inactive.'),('password','VARCHAR(255)','Hash kata laluan.'),
])
heading(doc,'18.2 audit_forms',2)
add_table(doc,['Field','Jenis','Keterangan'],[
('id','INT UNSIGNED PK','ID rekod audit.'),('perkara','VARCHAR(255)','Tajuk/perkara audit.'),('tarikh_mula','DATE','Tarikh mula tempoh maklum balas.'),('tarikh_akhir','DATE','Tarikh akhir tempoh maklum balas.'),('remarks','TEXT','Ringkasan perkara audit.'),('audit_approval_status','ENUM','Status umum audit.'),('created_by','FK users.id','Pengguna yang mendaftarkan audit.'),
])
heading(doc,'18.3 audit_feedbacks',2)
add_table(doc,['Field','Jenis','Keterangan'],[
('audit_form_id','FK audit_forms.id','Audit berkaitan.'),('submitted_by','FK users.id','Pengguna yang menghantar maklum balas.'),('submitted_unit','VARCHAR(150)','Bahagian/unit penghantar.'),('ringkasan','VARCHAR(255)','Ringkasan maklum balas.'),('maklum_balas','TEXT','Maklum balas penuh.'),('catatan_audit','TEXT','Catatan daripada Admin Audit.'),('attachment_path','VARCHAR(255)','Lokasi lampiran.'),('updated_at','TIMESTAMP','Tarikh hantar/kemaskini terkini.'),
])

heading(doc,'19. Validasi dan Peraturan Sistem',1)
add_table(doc,['Kawasan','Validasi / Peraturan'],[
('Login','Emel dan password mesti sepadan; akaun pending, rejected atau inactive tidak dibenarkan login.'),
('Daftar Audit','Tarikh akhir mesti sama atau selepas tarikh mula.'),
('Lampiran','Format dibenarkan: PDF, Word, Excel, JPG, JPEG dan PNG.'),
('Maklum Balas','Hanya bahagian ditugaskan boleh mencipta maklum balas.'),
('Tempoh Audit','Maklum balas disekat sebelum tarikh mula dan selepas tarikh akhir.'),
('Reset Password','Emel dan IC mesti wujud; kod verifikasi sah selama 15 minit.'),
('Role','Admin Audit tidak boleh mengubah role Pentadbir Sistem.'),
])

heading(doc,'20. Notifikasi Sistem',1)
add_table(doc,['Jenis Notifikasi','Penerima','Pencetus','Keterangan'],[
('audit_assigned','Pengguna dalam bahagian ditugaskan','Audit baru didaftarkan atau ditugaskan','Memaklumkan terdapat perkara audit yang memerlukan tindakan.'),
('catatan_audit','Bahagian yang menghantar maklum balas','Admin Audit menyimpan catatan audit','Memaklumkan bahagian bahawa terdapat catatan audit baharu.'),
('header notification','Pengguna berkaitan','Rekod notification belum dibaca','Dipaparkan di ikon loceng header.'),
])

heading(doc,'21. Backup dan Penyelenggaraan',1)
for item in ['Backup database audit_system sekurang-kurangnya sekali sehari atau mengikut polisi ICT organisasi.','Backup folder uploads/audit dan uploads/maklum_balas kerana lampiran tidak disimpan terus dalam database.','Simpan salinan SQL dan uploads di lokasi berasingan daripada server aplikasi.','Uji proses restore secara berkala supaya backup benar-benar boleh digunakan.','Semak saiz folder uploads dan arkib lampiran lama jika polisi organisasi membenarkan.']: bullet(doc,item)

heading(doc,'22. Deployment Ringkas',1)
add_table(doc,['Langkah','Keterangan'],[
('1. Sediakan Server','Pasang Apache/PHP/MySQL atau gunakan XAMPP untuk persekitaran tempatan.'),
('2. Salin Kod','Letakkan folder audit di htdocs atau document root server.'),
('3. Import Database','Import audit_system.sql atau biarkan includes/app.php bootstrap schema.'),
('4. Konfigurasi SMTP','Pastikan konfigurasi email reset password berfungsi.'),
('5. Semak Permission Folder','Pastikan folder uploads boleh ditulis oleh web server.'),
('6. Tukar Password Lalai','Tukar password akaun admin dan superadmin selepas deployment.'),
('7. Ujian Akhir','Uji login, daftar audit, maklum balas, notifikasi, reset password dan capaian pengguna.'),
])

heading(doc,'23. Senarai Ujian Penerimaan Pengguna (UAT)',1)
add_table(doc,['No.','Senario Ujian','Jangkaan Keputusan'],[
('1','Login menggunakan akaun aktif.','Pengguna berjaya masuk ke dashboard.'),('2','Login akaun inactive/pending.','Sistem menolak login dengan mesej sesuai.'),('3','Daftar audit baru dan pilih beberapa bahagian.','Audit disimpan dan notifikasi dihantar kepada bahagian.'),('4','Bahagian isi maklum balas dalam tempoh audit.','Maklum balas disimpan dan tarikh hantar dikemaskini.'),('5','Bahagian cuba isi maklum balas selepas tarikh akhir.','Sistem menyekat proses.'),('6','Admin Audit beri catatan audit.','Catatan disimpan dan notifikasi dipaparkan kepada bahagian.'),('7','Pentadbir Sistem ubah capaian bahagian.','Permission bahagian dikemaskini.'),('8','Pentadbir Sistem ubah capaian pengguna individu.','Permission individu override permission bahagian.'),('9','Reset password dengan emel dan IC sah.','Kod verifikasi dihantar dan password baru boleh disimpan.'),('10','Semak transaksi log.','Aktiviti penting pengguna direkod.'),
])

heading(doc,'24. Risiko dan Kawalan',1)
add_table(doc,['Risiko','Kesan','Kawalan Dicadangkan'],[
('Password lalai tidak ditukar','Akaun admin boleh diakses pihak tidak dibenarkan.','Wajib tukar password selepas deployment.'),('Tiada HTTPS','Data login boleh terdedah dalam rangkaian tidak selamat.','Gunakan SSL/TLS di server production.'),('Backup tidak konsisten','Data audit dan lampiran boleh hilang.','Jadual backup automatik dan ujian restore.'),('Permission terlalu luas','Pengguna boleh mengakses modul tidak berkaitan.','Semakan capaian berkala oleh Pentadbir Sistem.'),('Lampiran terlalu besar','Storage server cepat penuh.','Had saiz fail dan polisi arkib.'),
])

heading(doc,'25. Penutup',1)
doc.add_paragraph('Dokumentasi ini menerangkan fungsi utama, struktur data, aliran proses dan kawalan keselamatan bagi Dashboard Audit MAINPP. Dokumen ini boleh dijadikan rujukan pembangunan, latihan pengguna, UAT dan penyelenggaraan sistem pada masa hadapan.')

doc.save(EXPANDED_PATH)
print(EXPANDED_PATH)
