<?php

/*
 *
 * File ini bagian dari:
 *
 * OpenSID
 *
 * Sistem informasi desa sumber terbuka untuk memajukan desa
 *
 * Aplikasi dan source code ini dirilis berdasarkan lisensi GPL V3
 *
 * Hak Cipta 2009 - 2015 Combine Resource Institution (http://lumbungkomunitas.net/)
 * Hak Cipta 2016 - 2025 Perkumpulan Desa Digital Terbuka (https://opendesa.id)
 *
 * Dengan ini diberikan izin, secara gratis, kepada siapa pun yang mendapatkan salinan
 * dari perangkat lunak ini dan file dokumentasi terkait ("Aplikasi Ini"), untuk diperlakukan
 * tanpa batasan, termasuk hak untuk menggunakan, menyalin, mengubah dan/atau mendistribusikan,
 * asal tunduk pada syarat berikut:
 *
 * Pemberitahuan hak cipta di atas dan pemberitahuan izin ini harus disertakan dalam
 * setiap salinan atau bagian penting Aplikasi Ini. Barang siapa yang menghapus atau menghilangkan
 * pemberitahuan ini melanggar ketentuan lisensi Aplikasi Ini.
 *
 * PERANGKAT LUNAK INI DISEDIAKAN "SEBAGAIMANA ADANYA", TANPA JAMINAN APA PUN, BAIK TERSURAT MAUPUN
 * TERSIRAT. PENULIS ATAU PEMEGANG HAK CIPTA SAMA SEKALI TIDAK BERTANGGUNG JAWAB ATAS KLAIM, KERUSAKAN ATAU
 * KEWAJIBAN APAPUN ATAS PENGGUNAAN ATAU LAINNYA TERKAIT APLIKASI INI.
 *
 * @package   OpenSID
 * @author    Tim Pengembang OpenDesa
 * @copyright Hak Cipta 2009 - 2015 Combine Resource Institution (http://lumbungkomunitas.net/)
 * @copyright Hak Cipta 2016 - 2025 Perkumpulan Desa Digital Terbuka (https://opendesa.id)
 * @license   http://www.gnu.org/licenses/gpl.html GPL V3
 * @link      https://github.com/OpenSID/OpenSID
 *
 */

use App\Enums\JenisKelaminEnum;
use App\Enums\ListSasaranEnum;
use App\Enums\StatusDasarEnum;
use App\Models\Keluarga;
use App\Models\Pamong;
use App\Models\Penduduk;
use App\Models\Suplemen as ModelSuplemen;
use App\Models\SuplemenTerdata;
use App\Models\Wilayah;
use Illuminate\Support\Facades\View;
use OpenSpout\Common\Entity\Row;
use OpenSpout\Common\Entity\Style\Border;
use OpenSpout\Common\Entity\Style\BorderPart;
use OpenSpout\Common\Entity\Style\Color;
use OpenSpout\Common\Entity\Style\Style;
use OpenSpout\Reader\XLSX\Reader;
use OpenSpout\Writer\XLSX\Writer;

defined('BASEPATH') || exit('No direct script access allowed');

class Suplemen extends Admin_Controller
{
    public $modul_ini     = 'kependudukan';
    public $sub_modul_ini = 'data-suplemen';

    public function __construct()
    {
        parent::__construct();
        isCan('b');
    }

    protected static function validate($request = [])
    {
        return [
            'sasaran'    => $request['sasaran'],
            'nama'       => nomor_surat_keputusan($request['nama']),
            'keterangan' => strip_tags((string) $request['keterangan']),
        ];
    }

    protected static function validated_terdata($request = [])
    {
        $terdata = $request['sasaran'] == SuplemenTerdata::PENDUDUK
            ? ['penduduk_id' => $request['id_terdata']]
            : ['keluarga_id' => $request['id_terdata']];

        $result = [
            ...$terdata,
            'id_suplemen' => $request['id_suplemen'],
            'sasaran'     => $request['sasaran'],
            'keterangan'  => substr(htmlentities((string) $request['keterangan']), 0, 100),
        ];

        // Tambahkan `data_form_isian` hanya jika `input_data` ada dan valid
        if (isset($request['input_data']) && is_array($request['input_data'])) {
            $result['data_form_isian'] = $request['input_data'];
        }

        return $result;
    }

    public function index()
    {
        $list_sasaran = unserialize(SASARAN);

        return view('admin.suplemen.index', ['list_sasaran' => $list_sasaran]);
    }

    public function datatables()
    {
        if ($this->input->is_ajax_request()) {
            $sasaran = $this->input->get('sasaran');

            return datatables()->of(
                ModelSuplemen::withCount('terdata')->where('status', 1)
                    ->filter($sasaran)
            )
                ->addIndexColumn()
                ->addColumn('aksi', static function ($row): string {
                    $aksi = View::make('admin.layouts.components.buttons.rincian', [
                        'url' => "suplemen/rincian/{$row->id}",
                    ])->render();

                    if ($row->sumber !== 'OpenKab' && $row->config_id !== null) {
                        $aksi .= View::make('admin.layouts.components.buttons.impor', [
                            'url' => "suplemen/impor_data/{$row->id}",
                        ])->render();

                        $aksi .= View::make('admin.layouts.components.buttons.edit', [
                            'url' => "suplemen/form/{$row->id}",
                        ])->render();

                        $aksi .= View::make('admin.layouts.components.buttons.hapus', [
                            'url'           => "suplemen/delete/{$row->id}",
                            'confirmDelete' => true,
                        ])->render();
                    }

                    return $aksi;
                })
                ->editColumn('sasaran', static fn ($row): mixed => unserialize(SASARAN)[$row->sasaran])
                ->rawColumns(['aksi'])
                ->make();
        }

        return show_404();
    }

    public function form($id = '')
    {
        isCan('u');

        if ($id) {
            $action      = 'Ubah';
            $form_action = ci_route('suplemen.update', $id);
            $suplemen    = ModelSuplemen::with('terdata')->findOrFail($id);
            if ($suplemen->sumber == 'OpenKab' && $suplemen->config_id == null) {
                redirect_with('error', 'Anda tidak memiliki akses untuk halaman tersebut!');
            }
        } else {
            $action      = 'Tambah';
            $form_action = ci_route('suplemen.create');
            $suplemen    = null;
        }

        $list_sasaran = unserialize(SASARAN);

        return view('admin.suplemen.form', ['action' => $action, 'form_action' => $form_action, 'suplemen' => $suplemen, 'list_sasaran' => $list_sasaran]);
    }

    public function create(): void
    {
        isCan('u');

        try {
            ModelSuplemen::create(static::validate($this->request));
            redirect_with('success', 'Berhasil Tambah Data');
        } catch (Exception $e) {
            redirect_with('error', 'Gagal Tambah Data ' . $e->getMessage());
        }
    }

    public function update($id = ''): void
    {
        isCan('u');

        $update = ModelSuplemen::findOrFail($id);

        try {
            $data = static::validate($this->request);
            $data['sasaran'] ??= $update->sasaran;
            $update->update($data);
            redirect_with('success', 'Berhasil Ubah Data');
        } catch (Exception $e) {
            redirect_with('error', 'Gagal Ubah Data ' . $e->getMessage());
        }
    }

    public function delete($id): void
    {
        isCan('h');

        $suplemen = ModelSuplemen::findOrFail($id);
        if ($suplemen->sumber == 'OpenKab' && $suplemen->config_id == null) {
            redirect_with('error', 'Anda tidak memiliki akses untuk halaman tersebut!');
        }
        if ($suplemen->terdata()->count() > 0) {
            redirect_with('information', 'Suplemen tidak dapat dihapus karena masih memiliki peserta');
        }

        if ($suplemen->destroy($id)) {
            redirect_with('success', 'Berhasil Hapus Data');
        }

        redirect_with('error', 'Gagal Hapus Data');
    }

    public function rincian($id)
    {
        $sasaran  = unserialize(SASARAN);
        $suplemen = ModelSuplemen::findOrFail($id);
        $wilayah  = Wilayah::treeAccess();

        return view('admin.suplemen.detail', ['sasaran' => $sasaran, 'suplemen' => $suplemen, 'wilayah' => $wilayah]);
    }

    public function datatables_terdata()
    {
        if ($this->input->is_ajax_request()) {
            $id      = $this->input->get('id');
            $sasaran = $this->input->get('sasaran');
            $filters = [
                'sex'   => $this->input->get('sex'),
                'dusun' => $this->input->get('dusun'),
                'rw'    => $this->input->get('rw'),
                'rt'    => $this->input->get('rt'),
            ];
            $user          = ci_auth();
            $aksesWilayah  = [];
            $batasiWilayah = (bool) $user->batasi_wilayah;
            if ($batasiWilayah) {
                $aksesWilayah = $user->akses_wilayah ?? [];
            }

            return datatables()->of(SuplemenTerdata::anggota($sasaran, $id)->when($batasiWilayah, static fn ($q) => $q->whereIn('tweb_wil_clusterdesa.id', $aksesWilayah))->filter($filters))
                ->addColumn('ceklist', static function ($row) {
                    if (can('h')) {
                        if ($row->sumber != 'OpenKab' && $row->config_id != null) {
                            return '<input type="checkbox" name="id_cb[]" value="' . $row->id . '"/>';
                        }
                    }
                })
                ->addIndexColumn()
                ->addColumn('aksi', static function ($row): string {
                    $aksi = '';

                    if (can('u')) {
                        $sasaran = $row->sasaran == SuplemenTerdata::PENDUDUK
                            ? $row->penduduk_id
                            : $row->keluarga_id;
                        $aksi .= View::make('admin.layouts.components.buttons.edit', [
                            'url' => "suplemen/form_terdata/{$row->id_suplemen}/0/{$sasaran}",
                        ])->render();
                    }

                    if (can('h')) {
                        $aksi .= View::make('admin.layouts.components.buttons.hapus', [
                            'url'           => ci_route('suplemen.delete_terdata', $row->id),
                            'confirmDelete' => true,
                        ])->render();
                    }

                    return $aksi;
                })
                ->editColumn('tanggallahir', static fn ($row) => tgl_indo($row->tanggallahir))
                ->editColumn('sex', static fn ($row) => JenisKelaminEnum::valueOf($row->sex))
                ->editColumn(
                    'alamat',
                    static fn ($row): string => $row->alamat
                        ? $row->alamat . ' RT ' . $row->rt . ' / RW ' . $row->rw . ' ' . ucwords(setting('sebutan_dusun') . ' ' . $row->dusun)
                        : $row->alamat_sekarang . ' RT ' . $row->rt . ' / RW ' . $row->rw . ' ' . ucwords(setting('sebutan_dusun') . ' ' . $row->dusun)
                )
                ->rawColumns(['ceklist', 'aksi'])
                ->make();
        }

        return show_404();
    }

    public function form_terdata($id_suplemen, $aksi = 1, $id = '')
    {
        isCan('u');

        $suplemen      = ModelSuplemen::findOrFail($id_suplemen);
        $formData      = $suplemen->form_isian;
        $sasaran       = unserialize(SASARAN);
        $judul_sasaran = ListSasaranEnum::valueOf($suplemen->sasaran);
        $individu      = isset($_POST['id_terdata']) ? Penduduk::findOrFail($_POST['id_terdata']) : null;

        // Cek apakah field 'data_form_isian' ada di tabel 'suplemen_terdata'
        $data_form_isian = Illuminate\Support\Facades\Schema::hasColumn('suplemen_terdata', 'data_form_isian');

        if ($id) {
            $sasaran = $suplemen->sasaran == SuplemenTerdata::PENDUDUK
                ? 'penduduk_id'
                : 'keluarga_id';

            $action       = 'Ubah';
            $form_action  = ci_route('suplemen.update_terdata', $id);
            $terdata      = SuplemenTerdata::anggota($suplemen->sasaran, $suplemen->id)->where($sasaran, $id)->first();
            $existingData = $terdata->data_form_isian;
        } else {
            $action      = 'Tambah';
            $form_action = ci_route('suplemen.create_terdata', $aksi);
            $terdata     = null;
        }

        return view('admin.suplemen.form_terdata', ['action' => $action, 'form_action' => $form_action, 'suplemen' => $suplemen, 'terdata' => $terdata, 'sasaran' => $sasaran, 'judul_sasaran' => $judul_sasaran, 'individu' => $individu, 'formData' => $formData, 'existingData' => $existingData, 'data_form_isian' => $data_form_isian]);
    }

    public function create_terdata($aksi): void
    {
        isCan('u');
        if (SuplemenTerdata::create(static::validated_terdata($this->request))) {
            if ($aksi == 2) {
                redirect_with('success', 'Berhasil Tambah Data', 'suplemen/form_terdata/' . $this->request['id_suplemen'] . '/2');
            }
            redirect_with('success', 'Berhasil Tambah Data', 'suplemen/rincian/' . $this->request['id_suplemen']);
        }

        redirect_with('error', 'Gagal Tambah Data', 'suplemen/rincian/' . $this->request['id_suplemen']);
    }

    public function update_terdata($id = ''): void
    {
        isCan('u');

        $update = SuplemenTerdata::where('id_suplemen', $this->request['id_suplemen'])
            ->where(static function ($query) use ($id) {
                $query->where('penduduk_id', $id)
                    ->orWhere('keluarga_id', $id);
            })
            ->first();

        if (! $update) {
            redirect_with('error', 'Data tidak ditemukan', 'suplemen/rincian/' . $this->request['id_suplemen']);
        }

        // Data yang akan diperbarui
        $updateData = [
            'keterangan' => substr(htmlentities((string) $this->request['keterangan']), 0, 100),
        ];

        // Tambahkan `data_form_isian` hanya jika `input_data` ada dan valid
        if (isset($this->request['input_data']) && is_array($this->request['input_data'])) {
            $updateData['data_form_isian'] = $this->request['input_data'];
        }

        // Proses update
        if ($update->update($updateData)) {
            redirect_with('success', 'Berhasil Ubah Data', 'suplemen/rincian/' . $this->request['id_suplemen']);
        }

        redirect_with('error', 'Gagal Ubah Data', 'suplemen/rincian/' . $this->request['id_suplemen']);
    }

    public function delete_terdata($id): void
    {
        isCan('h');

        $id_suplemen = substr((string) $_SERVER['HTTP_REFERER'], -1);

        if (SuplemenTerdata::destroy($id)) {
            redirect_with('success', 'Berhasil Hapus Data', 'suplemen/rincian/' . $id_suplemen);
        }

        redirect_with('error', 'Gagal Hapus Data', 'suplemen/rincian/' . $id_suplemen);
    }

    public function delete_all_terdata(): void
    {
        isCan('h');

        $id_suplemen = substr((string) $_SERVER['HTTP_REFERER'], -1);

        if (SuplemenTerdata::destroy($this->request['id_cb'])) {
            redirect_with('success', 'Berhasil Hapus Data', 'suplemen/rincian/' . $id_suplemen);
        }

        redirect_with('error', 'Gagal Hapus Data', 'suplemen/rincian/' . $id_suplemen);
    }

    public function apipenduduksuplemen()
    {
        if ($this->input->is_ajax_request()) {
            $cari     = $this->input->get('q');
            $suplemen = $this->input->get('suplemen');
            $sasaran  = $this->input->get('sasaran');

            switch ($sasaran) {
                case 1:
                    $this->get_pilihan_penduduk($cari, $suplemen);
                    break;

                case 2:
                    $this->get_pilihan_kk($cari, $suplemen);
                    break;

                default:
            }
        }

        return show_404();
    }

    // $aksi = cetak/unduh
    public function dialog_daftar($id = 0, $aksi = '')
    {
        $data                = $this->modal_penandatangan();
        $data['aksi']        = $aksi;
        $data['form_action'] = site_url("{$this->controller}/daftar/{$id}/{$aksi}");

        return view('admin.layouts.components.ttd_pamong', $data);
    }

    // $aksi = cetak/unduh
    public function daftar($id = 0, $aksi = '')
    {
        if ($id > 0) {
            $data['suplemen']       = ModelSuplemen::findOrFail($id)->toArray();
            $data['terdata']        = SuplemenTerdata::anggota($data['suplemen']['sasaran'], $data['suplemen']['id'])->get()->toArray();
            $data['sasaran']        = unserialize(SASARAN);
            $data['pamong_ttd']     = Pamong::selectData()->where(['pamong_id' => $this->request['pamong_ttd']])->first()->toArray();
            $data['pamong_ketahui'] = Pamong::selectData()->where(['pamong_id' => $this->request['pamong_ketahui']])->first()->toArray();
            $data['aksi']           = $aksi;

            //pengaturan data untuk format cetak/ unduh
            $data['file']      = 'Laporan Suplemen ' . $data['suplemen']['nama'];
            $data['isi']       = 'admin.suplemen.cetak';
            $data['letak_ttd'] = ['2', '2', '3'];

            return view('admin.layouts.components.format_cetak', $data);
        }

        return show_404();
    }

    public function impor_data($id)
    {
        return view('admin.suplemen.impor', [
            'suplemen'    => ModelSuplemen::findOrFail($id),
            'form_action' => ci_route('suplemen.impor'),
            'formatImpor' => ci_route('unduh', encrypt(DEFAULT_LOKASI_IMPOR . 'format-impor-suplemen.xlsx')),
        ]);
    }

    public function impor()
    {
        isCan('u');
        $suplemen_id = $this->input->post('id_suplemen');

        $config = [
            'upload_path'   => sys_get_temp_dir(),
            'allowed_types' => 'xls|xlsx|xlsm',
        ];

        $this->load->library('upload');
        $this->upload->initialize($config);

        if (! $this->upload->do_upload('userfile')) {
            return session_error($this->upload->display_errors(null, null));
        }

        $upload = $this->upload->data();

        $reader = new Reader();
        $reader->open($upload['full_path']);

        $data_peserta      = [];
        $terdaftar_peserta = [];

        foreach ($reader->getSheetIterator() as $sheet) {
            $baris_pertama = true;
            $no_baris      = 0;
            $no_gagal      = 0;
            $no_sukses     = 0;
            $pesan         = '';

            $field = ['id', 'nama', 'sasaran', 'keterangan'];

            // Sheet Program
            if ($sheet->getName() === 'Peserta') {
                $suplemen_record = $this->get_suplemen($suplemen_id);
                $sasaran         = $suplemen_record['sasaran'];

                if ($sasaran == '1') {
                    $ambil_peserta     = SuplemenTerdata::where('id_suplemen', $suplemen_id)->pluck('penduduk_id');
                    $terdaftar_peserta = Penduduk::whereIn('id', $ambil_peserta)->pluck('nik')->toArray();
                } elseif ($sasaran == '2') {
                    $ambil_peserta     = SuplemenTerdata::where('id_suplemen', $suplemen_id)->pluck('keluarga_id');
                    $terdaftar_peserta = Keluarga::whereIn('id', $ambil_peserta)->pluck('no_kk')->toArray();
                }

                foreach ($sheet->getRowIterator() as $row) {
                    $cells = $row->getCells();

                    $peserta = trim((string) $cells[0]->getValue()); // NIK atau No_kk sesuai sasaran

                    // Data terakhir
                    if ($peserta === '###') {
                        break;
                    }

                    // Abaikan baris pertama / judul
                    if ($baris_pertama) {
                        $baris_pertama = false;

                        continue;
                    }

                    $no_baris++;

                    // Cek valid data peserta sesuai sasaran
                    $cek_peserta = $this->cek_peserta($peserta, $sasaran);
                    if (! in_array($peserta, $cek_peserta['valid'])) {
                        $no_gagal++;
                        $pesan .= '- Data peserta baris <b> Ke-' . ($no_baris) . ' / ' . $cek_peserta['sasaran_peserta'] . ' = ' . $peserta . '</b> tidak ditemukan <br>';

                        continue;
                    }
                    $penduduk_sasaran = $this->cek_penduduk($sasaran, $peserta);
                    if (! $penduduk_sasaran['id_terdata']) {
                        $no_gagal++;
                        $pesan .= '- Data peserta baris <b> Ke-' . ($no_baris) . ' / ' . $penduduk_sasaran['id_sasaran'] . ' = ' . $peserta . '</b> yang terdaftar tidak ditemukan <br>';

                        continue;
                    }
                    $id_terdata = $penduduk_sasaran['id_terdata'];

                    // Cek data peserta yg akan dimpor dan yg sudah ada
                    if (in_array($peserta, $terdaftar_peserta)) {
                        $no_gagal++;
                        $pesan .= '- Data peserta baris <b> Ke-' . ($no_baris) . '</b> sudah ada <br>';

                        continue;
                    }

                    $terdaftar_peserta[] = $peserta;

                    $terdata = $sasaran == SuplemenTerdata::PENDUDUK
                        ? ['penduduk_id' => $id_terdata]
                        : ['keluarga_id' => $id_terdata];

                    // Simpan data peserta yg diimpor dalam bentuk array
                    $simpan = [
                        ...$terdata,
                        'config_id'   => identitas('id'),
                        'id_suplemen' => $suplemen_id,
                        'sasaran'     => $sasaran, // Duplikasi
                        'keterangan'  => (string) $cells[1]->getValue(),
                    ];

                    $data_peserta[] = $simpan;
                    $no_sukses++;
                }

                // Proses impor peserta
                if ($no_baris <= 0) {
                    $pesan .= '- Data peserta tidak tersedia<br>';
                } else {
                    $this->impor_peserta($data_peserta);
                }
            }
        }

        $reader->close();

        $notif = [
            'gagal'  => $no_gagal,
            'sukses' => $no_sukses,
            'pesan'  => $pesan,
        ];

        set_session('notif', $notif);

        redirect("{$this->controller}/impor_data/{$suplemen_id}");
    }

    public function get_suplemen($id)
    {
        return ModelSuplemen::withCount('terdata as jml')
            ->find($id)
            ->toArray();
    }

    public function ekspor($id = 0): void
    {
        // Validasi apakah suplemen ditemukan
        $suplemen = ModelSuplemen::find($id);
        if (! $suplemen) {
            redirect_with('error', 'Suplemen tidak ditemukan.');
        }

        // Ambil data suplemen dan terdata
        $data_suplemen['suplemen'] = $suplemen->toArray();
        $data_suplemen['terdata']  = SuplemenTerdata::anggota($data_suplemen['suplemen']['sasaran'], $id)->get()->toArray();

        // Validasi apakah ada data terdata
        if (empty($data_suplemen['terdata'])) {
            redirect_with('error', 'Tidak ada data terdata untuk suplemen ini.', ci_route('suplemen.rincian', $id));
        }

        $file_name = namafile($data_suplemen['suplemen']['nama']) . '.xlsx';
        $writer    = new Writer();
        $writer->openToBrowser($file_name);

        // Ubah Nama Sheet
        $sheet = $writer->getCurrentSheet();
        $sheet->setName('Peserta');

        // Deklarasi Style
        $border = new Border(
            new BorderPart(Border::TOP, Color::GREEN, Border::WIDTH_THIN, Border::STYLE_SOLID),
            new BorderPart(Border::BOTTOM, Color::GREEN, Border::WIDTH_THIN, Border::STYLE_SOLID),
            new BorderPart(Border::LEFT, Color::GREEN, Border::WIDTH_THIN, Border::STYLE_SOLID),
            new BorderPart(Border::RIGHT, Color::GREEN, Border::WIDTH_THIN, Border::STYLE_SOLID)
        );

        $headerStyle = (new Style())
            ->setBorder($border)
            ->setBackgroundColor(Color::YELLOW)
            ->setFontBold();

        $footerStyle = (new Style())
            ->setBackgroundColor(Color::LIGHT_GREEN);

        // Cetak Header Tabel
        $values = ['Peserta', 'Nama', 'Tempat Lahir', 'Tanggal Lahir', 'Alamat', 'Keterangan'];

        // Mengambil key dari data_form_isian sebagai header
        $first_data = $data_suplemen['terdata'][0] ?? [];
        $dataForm   = $this->getDataFormIsian($first_data);

        if (! empty($dataForm)) {
            foreach ($dataForm as $key => $value) {
                $values[] = $this->formatColumnName($key);  // Mengubah format kolom
            }
        }

        $rowFromValues = Row::fromValues($values, $headerStyle);
        $writer->addRow($rowFromValues);

        // Cetak Data Anggota Suplemen
        foreach ($data_suplemen['terdata'] as $data) {
            $cells = [
                $data['nik'] ?? '-',
                strtoupper((string) $data['nama']),
                $data['tempatlahir'],
                tgl_indo_out($data['tanggallahir']),
                strtoupper($data['alamat'] . ' RT ' . $data['rt'] . ' / RW ' . $data['rw'] . ' ' . setting('sebutan_dusun') . ' ' . $data['dusun']),
                empty($data['keterangan']) ? '-' : $data['keterangan'],
            ];

            // Ambil data form isian
            $dataForm = $this->getDataFormIsian($data);

            if (! empty($dataForm)) {
                foreach ($dataForm as $value) {
                    $cells[] = $value;  // Menambahkan nilai form isian ke sel
                }
            }

            $singleRow = Row::fromValues($cells);
            $writer->addRow($singleRow);
        }

        // Menambahkan baris kosong
        $cells     = ['###', '', '', '', '', ''];
        $singleRow = Row::fromValues($cells);
        $writer->addRow($singleRow);

        // Cetak Catatan
        $array_catatan = [
            ['Catatan:', '', '', '', '', ''],
            ['1. Sesuaikan kolom peserta (A) berdasarkan sasaran : - penduduk = nik, - keluarga = no. kk', '', '', '', '', ''],
            ['2. Kolom Peserta (A) wajib di isi', '', '', '', '', ''],
            ['3. Kolom (B, C, D, E) diambil dari database kependudukan', '', '', '', '', ''],
            ['4. Kolom (F) opsional', '', '', '', '', ''],
        ];

        $rows_catatan = [];

        foreach ($array_catatan as $catatan) {
            $rows_catatan[] = Row::fromValues($catatan, $footerStyle);
        }
        $writer->addRows($rows_catatan);

        $writer->close();
    }

    private function get_pilihan_penduduk($cari, $terdata)
    {
        $id_suplemen = $terdata;
        $penduduk    = Penduduk::select(['id', 'nik', 'nama', 'id_cluster', 'kk_level'])
            ->when($cari, static function ($query) use ($cari) {
                return $query->where(static function ($q) use ($cari) {
                    $q->where('nik', 'like', "%{$cari}%")
                        ->orWhere('nama', 'like', "%{$cari}%");
                });
            })
            ->where('status_dasar', StatusDasarEnum::HIDUP) // Hanya penduduk dengan status hidup
            ->whereNotIn('id', static fn ($q) => $q->select(['penduduk_id'])->whereNotNull('penduduk_id')->from('suplemen_terdata')->where('id_suplemen', $id_suplemen))
            ->paginate(10);

        return json([
            'results' => collect($penduduk->items())
                ->map(static fn ($item): array => [
                    'id'   => $item->id,
                    'text' => 'NIK : ' . $item->nik . ' - ' . $item->nama . ' RT-' . $item->wilayah->rt . ', RW-' . $item->wilayah->rw . ', ' . strtoupper((string) setting('sebutan_dusun')) . ' ' . $item->wilayah->dusun,
                ]),
            'pagination' => [
                'more' => $penduduk->currentPage() < $penduduk->lastPage(),
            ],
        ]);
    }

    private function get_pilihan_kk($cari, $terdata)
    {
        $id_suplemen = $terdata;
        $penduduk    = Penduduk::select(['tweb_penduduk.id', 'tweb_penduduk.nik', 'keluarga_aktif.no_kk', 'tweb_penduduk.kk_level', 'tweb_penduduk.nama', 'tweb_penduduk.id_cluster'])
            ->leftJoin('tweb_penduduk_hubungan', static function ($join): void {
                $join->on('tweb_penduduk.kk_level', '=', 'tweb_penduduk_hubungan.id');
            })
            ->rightJoin('keluarga_aktif', static function ($join): void {
                $join->on('tweb_penduduk.id_kk', '=', 'keluarga_aktif.id');
            })
            ->when($cari, static function ($query) use ($cari): void {
                $query->where(static function ($q) use ($cari): void {
                    $q->where('tweb_penduduk.nik', 'like', "%{$cari}%")
                        ->orWhere('keluarga_aktif.no_kk', 'like', "%{$cari}%")
                        ->orWhere('tweb_penduduk.nama', 'like', "%{$cari}%");
                });
            })
            ->whereIn('tweb_penduduk.kk_level', ['1'])
            ->whereNotIn('tweb_penduduk.id_kk', static fn ($q) => $q->select(['keluarga_id'])->whereNotNull('keluarga_id')->from('suplemen_terdata')->where('id_suplemen', $id_suplemen))
            ->orderBy('tweb_penduduk.id_kk')
            ->paginate(10);

        return json([
            'results' => collect($penduduk->items())
                ->map(static fn ($item): array => [
                    'id'   => $item->id,
                    'text' => 'No KK : ' . $item->no_kk . ' - ' . $item->penduduk_hubungan . '- NIK : ' . $item->nik . ' - ' . $item->nama . ' RT-' . $item->wilayah->rt . ', RW-' . $item->wilayah->rw . ', ' . strtoupper((string) setting('sebutan_dusun')) . ' ' . $item->wilayah->dusun,
                ]),
            'pagination' => [
                'more' => $penduduk->currentPage() < $penduduk->lastPage(),
            ],
        ]);
    }

    private function cek_peserta(string $peserta = '', $sasaran = 1): false|array
    {
        if (in_array($peserta, [null, '-', ' ', '0'])) {
            return false;
        }

        switch ($sasaran) {
            case 1:
                // Penduduk
                $sasaran_peserta = 'NIK';

                $data = Penduduk::select(['id', 'nik as no'])->where('nik', $peserta)->get()->toArray();
                break;

            case 2:
                // Keluarga
                $sasaran_peserta = 'No. KK';

                $data = Keluarga::select(['id', 'no_kk as no'])->where('no_kk', $peserta)->get()->toArray();
                break;

            default:
                // Lainnya
                break;
        }

        return [
            'id'              => $data[0]['id'], // untuk nik, no_kk, no_rtm, kode konversi menjadi id issue #3417
            'sasaran_peserta' => $sasaran_peserta,
            'valid'           => array_column($data, 'no'), // untuk daftar valid anggota keluarga
        ];
    }

    private function cek_penduduk($sasaran, string $peserta): array
    {
        $terdata = [];
        if ($sasaran == '1') {
            $terdata['id_sasaran'] = 'NIK';
            $cek_penduduk          = Penduduk::where('nik', $peserta)->first()->toArray();
            if ($cek_penduduk['id']) {
                $terdata['id_terdata'] = $cek_penduduk['id'];
            }
        } elseif ($sasaran == '2') {
            $terdata['id_sasaran'] = 'KK';
            $keluarga              = Keluarga::with('kepalaKeluarga')->where('no_kk', $peserta)->first();
            $kepala_kk             = $keluarga->kepalaKeluarga->toArray();
            if ($kepala_kk['nik']) {
                $terdata['id_terdata'] = $kepala_kk['id_kk'];
            }
        }

        return $terdata;
    }

    private function impor_peserta(array $data_peserta = []): void
    {
        $this->session->success = 1;

        if ($data_peserta) {
            $outp = SuplemenTerdata::insert($data_peserta);
        }

        status_sukses($outp, true);
    }

    // Fungsi untuk memformat nama kolom, mengubah underscore menjadi spasi dan kapitalisasi setiap kata
    private function formatColumnName($columnName)
    {
        // Mengganti underscore dengan spasi
        $formatted = str_replace('_', ' ', $columnName);

        // Kapitalisasi setiap kata
        return ucwords($formatted);
    }

    // Fungsi untuk mengambil data_form_isian dengan validasi
    private function getDataFormIsian($data)
    {
        $dataForm = [];
        if (! empty($data['data_form_isian'])) {
            $dataForm = is_array($data['data_form_isian']) ? $data['data_form_isian'] : json_decode($data['data_form_isian'], true);
        }

        return is_array($dataForm) ? $dataForm : [];
    }
}
