<?php

namespace App\Controllers;

use App\Models\MahasiswaModel;
use App\Models\ProgramStudiModel;
use App\Models\PengaturanModel;
use App\Models\UserModel;

class Mahasiswa extends BaseController
{
    protected $mahasiswaModel;
    protected $programStudiModel;
    protected $pengaturanModel;
    protected $userModel;

    public function __construct()
    {
        $this->mahasiswaModel = new MahasiswaModel();
        $this->programStudiModel = new ProgramStudiModel();
        $this->pengaturanModel = new PengaturanModel();
        $this->userModel = new UserModel();
    }

    public function index()
    {
        // Parameter GET
        $search = $this->request->getGet('search');
        $prodi = $this->request->getGet('prodi');
        $angkatan = $this->request->getGet('angkatan');
        $status = $this->request->getGet('status');
        $perPage = $this->request->getGet('per_page') ?: 10;

        $this->mahasiswaModel->select('mahasiswa.*, program_studi.nama_prodi, users.username');
        $this->mahasiswaModel->join('program_studi', 'program_studi.id = mahasiswa.prodi_id', 'left');
        $this->mahasiswaModel->join('users', 'users.id = mahasiswa.user_id', 'left');

        // Filter: Search (NIM / Nama)
        if (!empty($search)) {
            $this->mahasiswaModel->groupStart()
                ->like('mahasiswa.nama_lengkap', $search)
                ->orLike('mahasiswa.nim', $search)
                ->groupEnd();
        }

        // Filter: Prodi
        if (!empty($prodi)) {
            $this->mahasiswaModel->where('mahasiswa.prodi_id', $prodi);
        }

        // Filter: Angkatan
        if (!empty($angkatan)) {
            $this->mahasiswaModel->where('mahasiswa.angkatan', $angkatan);
        }

        // Filter: Status
        if (!empty($status)) {
            $this->mahasiswaModel->where('mahasiswa.status_mahasiswa', $status);
        }

        $this->mahasiswaModel->orderBy('mahasiswa.angkatan', 'DESC');
        $this->mahasiswaModel->orderBy('mahasiswa.nama_lengkap', 'ASC');

        // Untuk Dropdown Filter
        $listProdi = $this->programStudiModel->findAll();
        $db = \Config\Database::connect();
        
        $queryAngkatan = $db->query("SELECT DISTINCT angkatan FROM mahasiswa WHERE angkatan IS NOT NULL AND angkatan != '' ORDER BY angkatan DESC");
        $listAngkatan = $queryAngkatan->getResultArray();
        
        $queryStatus = $db->query("SELECT DISTINCT status_mahasiswa FROM mahasiswa WHERE status_mahasiswa IS NOT NULL AND status_mahasiswa != '' ORDER BY status_mahasiswa ASC");
        $listStatus = $queryStatus->getResultArray();

        $data = [
            'title'     => 'Data Mahasiswa',
            'mahasiswa' => $this->mahasiswaModel->paginate($perPage, 'mahasiswa'),
            'pager'     => $this->mahasiswaModel->pager,
            'search'    => $search,
            'prodi_id'  => $prodi,
            'angkatan'  => $angkatan,
            'status'    => $status,
            'per_page'  => $perPage,
            'listProdi' => $listProdi,
            'listAngkatan' => $listAngkatan,
            'listStatus' => $listStatus
        ];

        return view('mahasiswa/index', $data);
    }

    public function syncPddikti()
    {
        $pddiktiUrl = $this->pengaturanModel->getValue('pddikti_url', '');
        $pddiktiUsername = $this->pengaturanModel->getValue('pddikti_username', '');
        $pddiktiPassword = $this->pengaturanModel->getValue('pddikti_password', '');

        if (empty($pddiktiUrl) || empty($pddiktiUsername) || empty($pddiktiPassword)) {
            session()->setFlashdata('error', 'Pengaturan PDDIKTI belum lengkap.');
            return redirect()->to('/mahasiswa');
        }

        try {
            $client = \Config\Services::curlrequest();

            // 1. Get Token
            $response = $client->post($pddiktiUrl, [
                'json' => [
                    'act'      => 'GetToken',
                    'username' => $pddiktiUsername,
                    'password' => $pddiktiPassword
                ],
                'verify' => false
            ]);

            $result = json_decode($response->getBody(), true);

            if ($result['error_code'] != 0) {
                session()->setFlashdata('error', 'Gagal mendapatkan token: ' . $result['error_desc']);
                return redirect()->to('/mahasiswa');
            }

            $token = $result['data']['token'];

            // 2. Get List Mahasiswa (with limits to avoid timeout, pulling 2000 for this example)
            $responseMhs = $client->post($pddiktiUrl, [
                'json' => [
                    'act'   => 'GetListMahasiswa',
                    'token' => $token,
                    'limit' => 2000
                ],
                'verify' => false
            ]);

            $resultMhs = json_decode($responseMhs->getBody(), true);

            if ($resultMhs['error_code'] != 0) {
                session()->setFlashdata('error', 'Gagal mengambil data mahasiswa: ' . $resultMhs['error_desc']);
                return redirect()->to('/mahasiswa');
            }

            $mahasiswaPddikti = $resultMhs['data'];

            $prodiLocal = $this->programStudiModel->findAll();
            $prodiMap = [];
            foreach ($prodiLocal as $p) {
                $prodiMap[$p['id_prodi_pddikti']] = $p['id'];
            }

            $db = \Config\Database::connect();
            $roleMahasiswa = $db->table('roles')->where('nama_role', 'Mahasiswa')->get()->getRowArray();
            $roleId = $roleMahasiswa ? $roleMahasiswa['id'] : 3;

            $successCount = 0;
            $updateCount = 0;

            foreach ($mahasiswaPddikti as $pddikti) {
                $idProdiPddikti = $pddikti['id_prodi'];
                $idProdi = $prodiMap[$idProdiPddikti] ?? null;

                if (!$idProdi) {
                    continue; // Lewati jika prodi tidak ada di lokal
                }

                $existingMhs = $this->mahasiswaModel->where('id_mahasiswa_pddikti', $pddikti['id_mahasiswa'])->first();

                $nim = trim($pddikti['nim'] ?? '');
                if (empty($nim)) {
                    continue; // Skip if no NIM
                }

                // Angkatan can be derived from id_periode
                $angkatan = !empty($pddikti['id_periode']) ? substr($pddikti['id_periode'], 0, 4) : null;

                // Status Mahasiswa Mapping
                $statusMap = [
                    'Aktif' => 'Aktif',
                    'Cuti' => 'Cuti',
                    'Lulus' => 'Lulus',
                    'Keluar' => 'Keluar',
                    'Putus Studi' => 'Drop Out'
                ];
                $pddiktiStatus = $pddikti['nama_status_mahasiswa'] ?? 'Aktif';
                $statusMhs = $statusMap[$pddiktiStatus] ?? 'Aktif';

                $tanggalLahir = !empty($pddikti['tanggal_lahir']) ? date('Y-m-d', strtotime($pddikti['tanggal_lahir'])) : null;

                $data = [
                    'id_mahasiswa_pddikti'    => $pddikti['id_mahasiswa'],
                    'id_registrasi_mahasiswa' => $pddikti['id_registrasi_mahasiswa'] ?? null,
                    'prodi_id'                => $idProdi,
                    'nim'                     => $nim,
                    'nama_lengkap'            => $pddikti['nama_mahasiswa'],
                    'tanggal_lahir'           => $tanggalLahir,
                    'jenis_kelamin'           => $pddikti['jenis_kelamin'] ?? 'L',
                    'agama'                   => $pddikti['nama_agama'] ?? null,
                    'status_mahasiswa'        => $statusMhs,
                    'angkatan'                => $angkatan
                ];

                try {
                    if ($existingMhs) {
                        // Cek jika butuh generate akun
                        $userId = $existingMhs['user_id'];
                        if (empty($userId)) {
                            $password = $tanggalLahir ? date('Ymd', strtotime($tanggalLahir)) : '123456';
                            $userData = [
                                'username'      => $nim,
                                'email'         => $nim . '@student.siakad.local',
                                'password_hash' => password_hash($password, PASSWORD_DEFAULT),
                                'role_id'       => $roleId,
                                'is_active'     => 1
                            ];
                            // check username exist first
                            $existingUser = $this->userModel->where('username', $nim)->first();
                            if(!$existingUser) {
                                $this->userModel->insert($userData);
                                $userId = $this->userModel->getInsertID();
                                $data['user_id'] = $userId;
                            } else {
                                $data['user_id'] = $existingUser['id'];
                            }
                        }

                        $this->mahasiswaModel->update($existingMhs['id'], $data);
                        $updateCount++;
                    } else {
                        // check if nim exists but different id_mahasiswa (rare but possible)
                        $mhsByNim = $this->mahasiswaModel->where('nim', $nim)->first();
                        if($mhsByNim) {
                            $this->mahasiswaModel->update($mhsByNim['id'], $data);
                            $updateCount++;
                        } else {
                            // Generate account
                            $password = $tanggalLahir ? date('Ymd', strtotime($tanggalLahir)) : '123456';
                            $existingUser = $this->userModel->where('username', $nim)->first();
                            if(!$existingUser) {
                                $userData = [
                                    'username'      => $nim,
                                    'email'         => $nim . '@student.siakad.local',
                                    'password_hash' => password_hash($password, PASSWORD_DEFAULT),
                                    'role_id'       => $roleId,
                                    'is_active'     => 1
                                ];
                                $this->userModel->insert($userData);
                                $data['user_id'] = $this->userModel->getInsertID();
                            } else {
                                $data['user_id'] = $existingUser['id'];
                            }
                            
                            $this->mahasiswaModel->insert($data);
                            $successCount++;
                        }
                    }
                } catch (\Exception $e) {
                    log_message('error', "Gagal sync NIM {$nim}: " . $e->getMessage());
                    continue; // Skip dan lanjut ke mahasiswa berikutnya
                }
            }

            session()->setFlashdata('success', "Berhasil menyinkronkan data mahasiswa. {$successCount} data baru, {$updateCount} diperbarui.");
            return redirect()->to('/mahasiswa');

        } catch (\Exception $e) {
            session()->setFlashdata('error', 'Terjadi kesalahan sistem: ' . $e->getMessage());
            return redirect()->to('/mahasiswa');
        }
    }

    public function migrateDb()
    {
        $db = \Config\Database::connect();
        $forge = \Config\Database::forge();
        
        $fields = [
            'id_mahasiswa_pddikti' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'id_registrasi_mahasiswa' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'angkatan' => ['type' => 'VARCHAR', 'constraint' => 4, 'null' => true],
            'nisn' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
            'npwp' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'jalan' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true],
            'dusun' => ['type' => 'VARCHAR', 'constraint' => 100, 'null' => true],
            'rt' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
            'rw' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
            'kelurahan' => ['type' => 'VARCHAR', 'constraint' => 100, 'null' => true],
            'kode_pos' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
            'kecamatan' => ['type' => 'VARCHAR', 'constraint' => 100, 'null' => true],
            'jenis_tinggal' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'telepon' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'email_pribadi' => ['type' => 'VARCHAR', 'constraint' => 100, 'null' => true],
            'penerima_kps' => ['type' => 'VARCHAR', 'constraint' => 10, 'null' => true],
            'nomor_kps' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'no_rekening' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'nama_pemilik_rekening' => ['type' => 'VARCHAR', 'constraint' => 100, 'null' => true],
            'nama_bank' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'nik_ayah' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
            'nama_ayah' => ['type' => 'VARCHAR', 'constraint' => 150, 'null' => true],
            'tanggal_lahir_ayah' => ['type' => 'DATE', 'null' => true],
            'pendidikan_ayah' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'pekerjaan_ayah' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'penghasilan_ayah' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'nik_ibu' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
            'nama_ibu_kandung' => ['type' => 'VARCHAR', 'constraint' => 150, 'null' => true],
            'tanggal_lahir_ibu' => ['type' => 'DATE', 'null' => true],
            'pendidikan_ibu' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'pekerjaan_ibu' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'penghasilan_ibu' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'nama_wali' => ['type' => 'VARCHAR', 'constraint' => 150, 'null' => true],
            'tanggal_lahir_wali' => ['type' => 'DATE', 'null' => true],
            'pendidikan_wali' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'pekerjaan_wali' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
            'penghasilan_wali' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
        ];

        foreach ($fields as $col => $def) {
            if (!$db->fieldExists($col, 'mahasiswa')) {
                $forge->addColumn('mahasiswa', [$col => $def]);
            }
        }
        
        return "Migration Complete!";
    }

    public function edit($id)
    {
        $mahasiswa = $this->mahasiswaModel->find($id);
        if (!$mahasiswa) {
            session()->setFlashdata('error', 'Data mahasiswa tidak ditemukan.');
            return redirect()->to('/mahasiswa');
        }

        $data = [
            'title' => 'Edit Mahasiswa',
            'mahasiswa' => $mahasiswa,
            'prodi' => $this->programStudiModel->findAll()
        ];
        return view('mahasiswa/edit', $data);
    }

    public function update($id)
    {
        $mahasiswa = $this->mahasiswaModel->find($id);
        if (!$mahasiswa) {
            return redirect()->to('/mahasiswa');
        }

        $post = $this->request->getPost();

        // 1. Validasi Input Dasar
        $validationRules = [
            'nim' => 'required',
            'nama_lengkap' => 'required',
            'prodi_id' => 'required',
            'jenis_kelamin' => 'required'
        ];

        if (!$this->validate($validationRules)) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        // --- Di sini idealnya Anda menambahkan logika UpdateBiodataMahasiswa ke PDDIKTI ---
        // Untuk tahap ini, kita utamakan menyimpan perubahan di lokal terlebih dahulu.

        $mhsData = [
            'prodi_id'                => $post['prodi_id'],
            'nim'                     => $post['nim'],
            'nama_lengkap'            => $post['nama_lengkap'],
            'tempat_lahir'            => $post['tempat_lahir'] ?? null,
            'tanggal_lahir'           => $post['tanggal_lahir'] ?? null,
            'jenis_kelamin'           => $post['jenis_kelamin'],
            'agama'                   => $post['agama'] ?? null,
            'kewarganegaraan'         => $post['kewarganegaraan'] ?? 'WNI',
            'nik'                     => $post['nik'] ?? null,
            'alamat'                  => $post['alamat'] ?? null,
            'no_hp'                   => $post['no_hp'] ?? null,
            'jalur_masuk'             => $post['jalur_masuk'] ?? null,
            'status_mahasiswa'        => $post['status_mahasiswa'] ?? 'Aktif',
            'angkatan'                => $post['angkatan'] ?? null,
            'nisn'                    => $post['nisn'] ?? null,
            'npwp'                    => $post['npwp'] ?? null,
            'jalan'                   => $post['jalan'] ?? null,
            'dusun'                   => $post['dusun'] ?? null,
            'rt'                      => $post['rt'] ?? null,
            'rw'                      => $post['rw'] ?? null,
            'kelurahan'               => $post['kelurahan'] ?? null,
            'kode_pos'                => $post['kode_pos'] ?? null,
            'kecamatan'               => $post['kecamatan'] ?? null,
            'jenis_tinggal'           => $post['jenis_tinggal'] ?? null,
            'telepon'                 => $post['telepon'] ?? null,
            'email_pribadi'           => $post['email_pribadi'] ?? null,
            'penerima_kps'            => $post['penerima_kps'] ?? '0',
            'nomor_kps'               => $post['nomor_kps'] ?? null,
            'nik_ayah'                => $post['nik_ayah'] ?? null,
            'nama_ayah'               => $post['nama_ayah'] ?? null,
            'tanggal_lahir_ayah'      => (!empty($post['tanggal_lahir_ayah'])) ? $post['tanggal_lahir_ayah'] : null,
            'pendidikan_ayah'         => $post['pendidikan_ayah'] ?? null,
            'pekerjaan_ayah'          => $post['pekerjaan_ayah'] ?? null,
            'penghasilan_ayah'        => $post['penghasilan_ayah'] ?? null,
            'nik_ibu'                 => $post['nik_ibu'] ?? null,
            'nama_ibu_kandung'        => $post['nama_ibu_kandung'] ?? null,
            'tanggal_lahir_ibu'       => (!empty($post['tanggal_lahir_ibu'])) ? $post['tanggal_lahir_ibu'] : null,
            'pendidikan_ibu'          => $post['pendidikan_ibu'] ?? null,
            'pekerjaan_ibu'           => $post['pekerjaan_ibu'] ?? null,
            'penghasilan_ibu'         => $post['penghasilan_ibu'] ?? null,
            'nama_wali'               => $post['nama_wali'] ?? null,
            'tanggal_lahir_wali'      => (!empty($post['tanggal_lahir_wali'])) ? $post['tanggal_lahir_wali'] : null,
            'pendidikan_wali'         => $post['pendidikan_wali'] ?? null,
            'pekerjaan_wali'          => $post['pekerjaan_wali'] ?? null,
            'penghasilan_wali'        => $post['penghasilan_wali'] ?? null,
            'tanggal_daftar'          => $post['tanggal_daftar'] ?? null,
            'pembiayaan_awal'         => $post['pembiayaan_awal'] ?? null,
            'biaya_masuk'             => $post['biaya_masuk'] ?? null,
            'asal_pt'                 => $post['asal_pt'] ?? null,
            'asal_prodi'              => $post['asal_prodi'] ?? null,
        ];

        $this->mahasiswaModel->update($id, $mhsData);

        session()->setFlashdata('success', 'Data Mahasiswa berhasil diperbarui.');
        return redirect()->to('/mahasiswa');
    }



    public function searchPT()
    {
        $keyword = $this->request->getGet('q');
        if (empty($keyword)) return $this->response->setJSON([]);

        $pddiktiUrl = $this->pengaturanModel->getValue('pddikti_url', '');
        $pddiktiUsername = $this->pengaturanModel->getValue('pddikti_username', '');
        $pddiktiPassword = $this->pengaturanModel->getValue('pddikti_password', '');

        if (empty($pddiktiUrl)) return $this->response->setJSON([]);

        try {
            // Tutup session sementara untuk menghindari session lock jika API lambat
            session_write_close();

            $client = \Config\Services::curlrequest();
            $response = $client->post($pddiktiUrl, [
                'json' => ['act' => 'GetToken', 'username' => $pddiktiUsername, 'password' => $pddiktiPassword],
                'verify' => false,
                'timeout' => 30,
                'curl' => [CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4]
            ]);
            $token = json_decode($response->getBody(), true)['data']['token'] ?? null;

            if (!$token) {
                return $this->response->setJSON([['id' => '0', 'text' => 'Gagal mendapatkan token dari PDDIKTI']]);
            }
        } catch (\Throwable $e) {
            return $this->response->setJSON([['id' => '0', 'text' => 'API Error (GetToken): ' . $e->getMessage()]]);
        }

        try {
            $responsePT = $client->post($pddiktiUrl, [
                'json' => [
                    'act' => 'GetPerguruanTinggi',
                    'token' => $token,
                    'filter' => "nama_perguruan_tinggi LIKE '%" . addslashes($keyword) . "%' OR kode_perguruan_tinggi LIKE '%" . addslashes($keyword) . "%'",
                    'limit' => 20
                ],
                'verify' => false,
                'timeout' => 30,
                'curl' => [CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4]
            ]);
            $body = json_decode($responsePT->getBody(), true);
            $dataPT = isset($body['data']) && is_array($body['data']) ? $body['data'] : [];

            $results = [];
            foreach ($dataPT as $pt) {
                $results[] = [
                    'id' => $pt['id_perguruan_tinggi'],
                    'text' => $pt['kode_perguruan_tinggi'] . ' - ' . $pt['nama_perguruan_tinggi']
                ];
            }
            if(empty($results)) {
                $results[] = ['id' => '0', 'text' => 'Pencarian tidak ditemukan'];
            }
            return $this->response->setJSON($results);
        } catch (\Throwable $e) {
            return $this->response->setJSON([['id' => '0', 'text' => 'API Error (searchPT): ' . $e->getMessage()]]);
        }
    }

    public function syncPT()
    {
        set_time_limit(0);
        $db = \Config\Database::connect();
        
        $offset = (int) $this->request->getGet('offset');
        $limit = 100; // Dikurangi dari 500 ke 100 agar query API PDDIKTI tidak terlalu berat dan mencegah timeout

        if ($offset === 0) {
            // First run, create table and truncate
            if (!$db->tableExists('ref_perguruan_tinggi')) {
                $forge = \Config\Database::forge();
                $forge->addField([
                    'id_perguruan_tinggi' => ['type' => 'VARCHAR', 'constraint' => '50', 'null' => false],
                    'kode_perguruan_tinggi' => ['type' => 'VARCHAR', 'constraint' => '20', 'null' => true],
                    'nama_perguruan_tinggi' => ['type' => 'VARCHAR', 'constraint' => '255', 'null' => false],
                ]);
                $forge->addKey('id_perguruan_tinggi', true);
                $forge->createTable('ref_perguruan_tinggi', true);
            }
            $db->table('ref_perguruan_tinggi')->truncate();
        }

        $pddiktiUrl = $this->pengaturanModel->getValue('pddikti_url', '');
        $pddiktiUsername = $this->pengaturanModel->getValue('pddikti_username', '');
        $pddiktiPassword = $this->pengaturanModel->getValue('pddikti_password', '');

        $client = \Config\Services::curlrequest();

        try {
            $response = $client->post($pddiktiUrl, [
                'json' => [
                    'act' => 'GetToken',
                    'username' => $pddiktiUsername,
                    'password' => $pddiktiPassword
                ],
                'verify' => false,
                'http_errors' => false
            ]);
            $res = json_decode($response->getBody(), true);
            if (!$res || $res['error_code'] != 0) {
                return $this->response->setJSON(['status' => 'error', 'message' => 'Gagal mendapatkan token PDDIKTI']);
            }
            $token = $res['data']['token'];

            $resPT = $client->post($pddiktiUrl, [
                'json' => [
                    'act' => 'GetPerguruanTinggi',
                    'token' => $token,
                    'filter' => '', 
                    'limit' => $limit,
                    'offset' => $offset
                ],
                'verify' => false,
                'timeout' => 180, // Ditingkatkan menjadi 180 detik
                'http_errors' => false
            ]);
            $ptResult = json_decode($resPT->getBody(), true);
            
            if (!$ptResult || $ptResult['error_code'] != 0) {
                return $this->response->setJSON(['status' => 'error', 'message' => 'Gagal mengunduh referensi perguruan tinggi pada offset ' . $offset]);
            }

            $batch = $ptResult['data'];
            if (empty($batch)) {
                return $this->response->setJSON([
                    'status' => 'success', 
                    'done' => true,
                    'message' => 'Semua data Perguruan Tinggi berhasil disinkronisasi ke database lokal!'
                ]);
            }

            $insertData = [];
            foreach ($batch as $p) {
                $insertData[] = [
                    'id_perguruan_tinggi' => $p['id_perguruan_tinggi'],
                    'kode_perguruan_tinggi' => $p['kode_perguruan_tinggi'] ?? null,
                    'nama_perguruan_tinggi' => $p['nama_perguruan_tinggi']
                ];
            }
            $db->table('ref_perguruan_tinggi')->insertBatch($insertData);

            return $this->response->setJSON([
                'status' => 'success',
                'done' => false,
                'next_offset' => $offset + $limit,
                'count' => count($batch),
                'message' => 'Berhasil menarik ' . count($batch) . ' data (offset: ' . $offset . ')'
            ]);

        } catch (\Exception $e) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Terjadi kesalahan sistem: ' . $e->getMessage()]);
        }
    }

    public function searchProdi()
    {
        $id_pt = $this->request->getGet('id_pt');
        if (empty($id_pt)) return $this->response->setJSON([]);

        $pddiktiUrl = $this->pengaturanModel->getValue('pddikti_url', '');
        $pddiktiUsername = $this->pengaturanModel->getValue('pddikti_username', '');
        $pddiktiPassword = $this->pengaturanModel->getValue('pddikti_password', '');

        if (empty($pddiktiUrl)) return $this->response->setJSON([]);

        try {
            // Tutup session sementara untuk menghindari session lock jika API lambat
            session_write_close();

            $client = \Config\Services::curlrequest();
            $response = $client->post($pddiktiUrl, [
                'json' => ['act' => 'GetToken', 'username' => $pddiktiUsername, 'password' => $pddiktiPassword],
                'verify' => false,
                'timeout' => 30,
                'curl' => [CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4]
            ]);
            $token = json_decode($response->getBody(), true)['data']['token'] ?? null;

            if (!$token) {
                return $this->response->setJSON([['id' => '0', 'text' => 'Gagal mendapatkan token dari PDDIKTI']]);
            }
        } catch (\Throwable $e) {
            return $this->response->setJSON([['id' => '0', 'text' => 'API Error (GetToken): ' . $e->getMessage()]]);
        }

        try {
            $responseProdi = $client->post($pddiktiUrl, [
                'json' => [
                    'act' => 'GetProdi',
                    'token' => $token,
                    'filter' => "id_perguruan_tinggi='" . $id_pt . "'",
                    'limit' => 50
                ],
                'verify' => false,
                'timeout' => 30,
                'curl' => [CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4]
            ]);
            $body = json_decode($responseProdi->getBody(), true);
            $dataProdi = isset($body['data']) && is_array($body['data']) ? $body['data'] : [];

            $results = [];
            foreach ($dataProdi as $prodi) {
                $results[] = [
                    'id' => $prodi['id_prodi'],
                    'text' => $prodi['kode_program_studi'] . ' - ' . $prodi['nama_program_studi'] . ' (' . $prodi['nama_jenjang_pendidikan'] . ')'
                ];
            }
            if(empty($results)) {
                $results[] = ['id' => '0', 'text' => 'Program studi tidak ditemukan'];
            }
            return $this->response->setJSON($results);
        } catch (\Throwable $e) {
            return $this->response->setJSON([['id' => '0', 'text' => 'API Error (GetProdi): ' . $e->getMessage()]]);
        }
    }

    public function searchWilayah()
    {
        $q = $this->request->getGet('q');
        if (empty($q) || strlen($q) < 3) {
            return $this->response->setJSON([]);
        }

        try {
            $wilayahModel = new \App\Models\RefWilayahModel();
            // Since we are searching only Kecamatan, we can filter or just search by name
            $results = $wilayahModel->searchWilayahFull($q, 15);
            
            return $this->response->setJSON($results);
        } catch (\Exception $e) {
            return $this->response->setJSON([]);
        }
    }

    public function syncWilayah()
    {
        // 1. Pastikan tabel ref_wilayah ada
        $db = \Config\Database::connect();
        if (!$db->tableExists('ref_wilayah')) {
            $forge = \Config\Database::forge();
            $forge->addField([
                'id_wilayah' => ['type' => 'VARCHAR', 'constraint' => '8', 'null' => false],
                'nama_wilayah' => ['type' => 'VARCHAR', 'constraint' => '255', 'null' => false],
                'id_induk_wilayah' => ['type' => 'VARCHAR', 'constraint' => '8', 'null' => true],
            ]);
            $forge->addKey('id_wilayah', true);
            $forge->addKey('id_induk_wilayah');
            $forge->addKey('nama_wilayah');
            $forge->createTable('ref_wilayah', true);
        }

        // 2. Ambil token PDDIKTI
        $pddiktiUrl = $this->pengaturanModel->getValue('pddikti_url', '');
        $pddiktiUsername = $this->pengaturanModel->getValue('pddikti_username', '');
        $pddiktiPassword = $this->pengaturanModel->getValue('pddikti_password', '');

        $client = \Config\Services::curlrequest();

        try {
            $response = $client->post($pddiktiUrl, [
                'json' => [
                    'act' => 'GetToken',
                    'username' => $pddiktiUsername,
                    'password' => $pddiktiPassword
                ],
                'verify' => false,
                'http_errors' => false
            ]);
            $res = json_decode($response->getBody(), true);
            if (!$res || $res['error_code'] != 0) {
                return $this->response->setJSON(['status' => 'error', 'message' => 'Gagal mendapatkan token PDDIKTI']);
            }
            $token = $res['data']['token'];

            // 3. Ambil seluruh data wilayah dari PDDIKTI (Tidak menggunakan filter karena ingin ditarik semua)
            $resWil = $client->post($pddiktiUrl, [
                'json' => [
                    'act' => 'GetWilayah',
                    'token' => $token,
                    'filter' => '', // kosong = ambil semua
                    'limit' => 100000 // asumsi max wilayah 100rb
                ],
                'verify' => false,
                'http_errors' => false
            ]);
            $wilResult = json_decode($resWil->getBody(), true);
            
            if (!$wilResult || $wilResult['error_code'] != 0) {
                return $this->response->setJSON(['status' => 'error', 'message' => 'Gagal mengunduh referensi wilayah']);
            }

            $dataWilayah = $wilResult['data'];
            
            if (empty($dataWilayah)) {
                return $this->response->setJSON(['status' => 'error', 'message' => 'Data wilayah dari PDDIKTI kosong']);
            }

            // 4. Kosongkan tabel lokal dan bulk insert
            $wilayahModel = new \App\Models\RefWilayahModel();
            $db->table('ref_wilayah')->truncate();

            // Insert in chunks of 500 to prevent memory issues
            $chunks = array_chunk($dataWilayah, 500);
            foreach ($chunks as $chunk) {
                $insertData = [];
                foreach ($chunk as $w) {
                    $insertData[] = [
                        'id_wilayah' => $w['id_wilayah'],
                        'nama_wilayah' => $w['nama_wilayah'],
                        'id_induk_wilayah' => $w['id_induk_wilayah'] ?? null
                    ];
                }
                $wilayahModel->insertBatch($insertData);
            }

            return $this->response->setJSON([
                'status' => 'success', 
                'message' => count($dataWilayah) . ' data wilayah berhasil disinkronisasi ke database lokal!'
            ]);

        } catch (\Exception $e) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Terjadi kesalahan sistem: ' . $e->getMessage()]);
        }
    }

    public function create()
    {
        $data = [
            'title' => 'Tambah Mahasiswa (PDDIKTI)',
            'prodi' => $this->programStudiModel->findAll()
        ];
        return view('mahasiswa/create', $data);
    }

    public function store()
    {
        $rules = [
            'nama_lengkap' => 'required',
            'tempat_lahir' => 'required',
            'tanggal_lahir' => 'required',
            'jenis_kelamin' => 'required',
            'agama' => 'required',
            'nik' => 'required|exact_length[16]',
            'nama_ibu_kandung' => 'required',
            'nim' => 'required',
            'prodi_id' => 'required',
            'jenis_daftar' => 'required',
            'periode_masuk' => 'required'
        ];

        if (!$this->validate($rules)) {
            session()->setFlashdata('error', 'Validasi gagal. Pastikan form diisi dengan benar (NIK harus 16 digit, Nama Ibu wajib ada).');
            return redirect()->back()->withInput();
        }

        $post = $this->request->getPost();

        // Siapkan API PDDIKTI
        $pddiktiUrl = $this->pengaturanModel->getValue('pddikti_url', '');
        $pddiktiUsername = $this->pengaturanModel->getValue('pddikti_username', '');
        $pddiktiPassword = $this->pengaturanModel->getValue('pddikti_password', '');

        $client = \Config\Services::curlrequest();

        // 1. Get Token
        try {
            $response = $client->post($pddiktiUrl, [
                'json' => [
                    'act' => 'GetToken',
                    'username' => $pddiktiUsername,
                    'password' => $pddiktiPassword
                ],
                'verify' => false,
                'timeout' => 30,
                'http_errors' => false
            ]);
            $res = json_decode($response->getBody(), true);
            if (!$res || $res['error_code'] != 0) {
                session()->setFlashdata('error', 'Gagal koneksi ke PDDIKTI: Token error.');
                return redirect()->back()->withInput();
            }
            $token = $res['data']['token'];

            // 2. Insert Biodata Mahasiswa
            $biodataRecord = [
                'nama_mahasiswa' => $post['nama_lengkap'],
                'jenis_kelamin' => $post['jenis_kelamin'],
                'tempat_lahir' => $post['tempat_lahir'],
                'tanggal_lahir' => $post['tanggal_lahir'], // format yyyy-mm-dd
                'id_agama' => (int)$post['agama'],
                'nik' => $post['nik'],
                'nisn' => $post['nisn'] ?? '',
                'npwp' => $post['npwp'] ?? '',
                'kewarganegaraan' => 'ID', // WNI default
                'jalan' => $post['jalan'] ?? '',
                'dusun' => $post['dusun'] ?? '',
                'rt' => $post['rt'] ? (int)$post['rt'] : 0,
                'rw' => $post['rw'] ? (int)$post['rw'] : 0,
                'kelurahan' => $post['kelurahan'],
                'kode_pos' => $post['kode_pos'] ? (int)$post['kode_pos'] : 0,
                'id_wilayah' => $post['id_wilayah'] ?? '000000', // Dari Autocomplete
                'id_jenis_tinggal' => (int)($post['jenis_tinggal'] ?? 1),
                'id_alat_transportasi' => (int)($post['alat_transportasi'] ?? 1),
                'telepon' => $post['telepon'] ?? '',
                'handphone' => $post['no_hp'],
                'email' => $post['email_pribadi'],
                'penerima_kps' => (int)($post['penerima_kps'] ?? 0),
                
                // Data Ayah
                'nik_ayah' => $post['nik_ayah'] ?? '',
                'nama_ayah' => $post['nama_ayah'] ?? '',
                'tanggal_lahir_ayah' => $post['tanggal_lahir_ayah'] ?: null,
                'id_pendidikan_ayah' => (int)($post['pendidikan_ayah'] ?? 0),
                'id_pekerjaan_ayah' => (int)($post['pekerjaan_ayah'] ?? 1),
                'id_penghasilan_ayah' => (int)($post['penghasilan_ayah'] ?? 1),
                
                // Data Ibu
                'nik_ibu' => $post['nik_ibu'] ?? '',
                'nama_ibu_kandung' => $post['nama_ibu_kandung'],
                'tanggal_lahir_ibu' => $post['tanggal_lahir_ibu'] ?: null,
                'id_pendidikan_ibu' => (int)($post['pendidikan_ibu'] ?? 0),
                'id_pekerjaan_ibu' => (int)($post['pekerjaan_ibu'] ?? 1),
                'id_penghasilan_ibu' => (int)($post['penghasilan_ibu'] ?? 0),
                
                // Data Wali
                'nama_wali' => $post['nama_wali'] ?? '',
                'tanggal_lahir_wali' => $post['tanggal_lahir_wali'] ?: null,
                'id_pendidikan_wali' => (int)($post['pendidikan_wali'] ?? 0),
                'id_pekerjaan_wali' => (int)($post['pekerjaan_wali'] ?? 0),
                'id_penghasilan_wali' => (int)($post['penghasilan_wali'] ?? 0),
                
                // Kebutuhan Khusus
                'id_kebutuhan_khusus_mahasiswa' => (int)($post['kebutuhan_khusus_mhs'] ?? 0),
                'id_kebutuhan_khusus_ayah' => (int)($post['kebutuhan_khusus_ayah'] ?? 0),
                'id_kebutuhan_khusus_ibu' => (int)($post['kebutuhan_khusus_ibu'] ?? 0)
            ];

            // Remove nulls for dates if empty to prevent PDDIKTI error
            if(empty($biodataRecord['tanggal_lahir_ayah'])) unset($biodataRecord['tanggal_lahir_ayah']);
            if(empty($biodataRecord['tanggal_lahir_ibu'])) unset($biodataRecord['tanggal_lahir_ibu']);
            if(empty($biodataRecord['tanggal_lahir_wali'])) unset($biodataRecord['tanggal_lahir_wali']);

            $resBio = $client->post($pddiktiUrl, [
                'json' => [
                    'act' => 'InsertBiodataMahasiswa',
                    'token' => $token,
                    'record' => $biodataRecord
                ],
                'verify' => false,
                'timeout' => 30,
                'http_errors' => false
            ]);
            $bioResult = json_decode($resBio->getBody(), true);
            
            if (!$bioResult || $bioResult['error_code'] != 0) {
                $errDesc = strtolower($bioResult['error_desc'] ?? '');
                if (strpos($errDesc, 'sudah ada') !== false || strpos($errDesc, 'terdaftar') !== false || strpos($errDesc, 'digunakan') !== false) {
                    // Coba ambil id_mahasiswa yang sudah ada
                    $resGetBio = $client->post($pddiktiUrl, [
                        'json' => [
                            'act' => 'GetBiodataMahasiswa',
                            'token' => $token,
                            'filter' => "nik='{$post['nik']}'",
                            'limit' => 1
                        ],
                        'verify' => false,
                        'timeout' => 30,
                        'http_errors' => false
                    ]);
                    $getBio = json_decode($resGetBio->getBody(), true);
                    if ($getBio && $getBio['error_code'] == 0 && !empty($getBio['data'])) {
                        $id_mahasiswa_pddikti = $getBio['data'][0]['id_mahasiswa'];
                    } else {
                        session()->setFlashdata('error', 'Gagal Push Biodata: ' . ($bioResult['error_desc'] ?? 'Unknown Error'));
                        return redirect()->back()->withInput();
                    }
                } else {
                    session()->setFlashdata('error', 'Gagal Push Biodata: ' . ($bioResult['error_desc'] ?? 'Unknown Error'));
                    return redirect()->back()->withInput();
                }
            } else {
                $id_mahasiswa_pddikti = $bioResult['data']['id_mahasiswa'];
            }

            // 3. Get Profil PT for id_perguruan_tinggi
            $resPt = $client->post($pddiktiUrl, [
                'json' => ['act' => 'GetProfilPT', 'token' => $token],
                'verify' => false,
                'timeout' => 30,
                'http_errors' => false
            ]);
            $ptResult = json_decode($resPt->getBody(), true);
            $id_perguruan_tinggi = $ptResult['data'][0]['id_perguruan_tinggi'] ?? null;

            if (!$id_perguruan_tinggi) {
                session()->setFlashdata('error', 'Gagal mengambil ID Perguruan Tinggi dari PDDIKTI.');
                return redirect()->back()->withInput();
            }

            // 4. Get id_prodi from local and PDDIKTI
            $prodi = $this->programStudiModel->find($post['prodi_id']);
            $id_prodi_pddikti = $prodi['id_prodi_pddikti'];

            // 5. Insert Riwayat Pendidikan Mahasiswa
            $riwayatRecord = [
                'id_mahasiswa' => $id_mahasiswa_pddikti,
                'nim' => $post['nim'],
                'id_jenis_daftar' => (int)$post['jenis_daftar'],
                'id_jalur_daftar' => (int)($post['jalur_daftar'] ?? 8), // Default: Seleksi Mandiri
                'id_periode_masuk' => $post['periode_masuk'],
                'tanggal_daftar' => $post['tanggal_daftar'], 
                'id_perguruan_tinggi' => $id_perguruan_tinggi,
                'id_prodi' => $id_prodi_pddikti,
                'id_pembiayaan' => (int)($post['pembiayaan_awal'] ?? 1),
                'biaya_masuk' => (int)($post['biaya_masuk'] ?? 0)
            ];

            if (in_array((int)$post['jenis_daftar'], [2, 11]) && !empty($post['asal_pt'])) {
                $riwayatRecord['id_perguruan_tinggi_asal'] = $post['asal_pt'];
                $riwayatRecord['id_prodi_asal'] = $post['asal_prodi'];
            }

            $resRiwayat = $client->post($pddiktiUrl, [
                'json' => [
                    'act' => 'InsertRiwayatPendidikanMahasiswa',
                    'token' => $token,
                    'record' => $riwayatRecord
                ],
                'verify' => false,
                'timeout' => 30,
                'http_errors' => false
            ]);
            $riwayatResult = json_decode($resRiwayat->getBody(), true);

            $riwayatSuccess = true;
            $riwayatErrorMsg = '';
            $id_registrasi_mahasiswa = null;

            if (!$riwayatResult || $riwayatResult['error_code'] != 0) {
                $errDescRiw = strtolower($riwayatResult['error_desc'] ?? '');
                if (strpos($errDescRiw, 'sudah ada') !== false || strpos($errDescRiw, 'terdaftar') !== false) {
                    $resGetRiw = $client->post($pddiktiUrl, [
                        'json' => [
                            'act' => 'GetListRiwayatPendidikanMahasiswa',
                            'token' => $token,
                            'filter' => "id_mahasiswa='{$id_mahasiswa_pddikti}' AND id_prodi='{$id_prodi_pddikti}'",
                            'limit' => 1
                        ],
                        'verify' => false,
                        'timeout' => 30,
                        'http_errors' => false
                    ]);
                    $getRiw = json_decode($resGetRiw->getBody(), true);
                    if ($getRiw && $getRiw['error_code'] == 0 && !empty($getRiw['data'])) {
                        $id_registrasi_mahasiswa = $getRiw['data'][0]['id_registrasi_mahasiswa'];
                    } else {
                        $riwayatSuccess = false;
                        $riwayatErrorMsg = $riwayatResult['error_desc'] ?? 'Unknown Error';
                    }
                } else {
                    $riwayatSuccess = false;
                    $riwayatErrorMsg = $riwayatResult['error_desc'] ?? 'Unknown Error';
                }
            } else {
                $id_registrasi_mahasiswa = $riwayatResult['data']['id_registrasi_mahasiswa'];
            }

            // 6. Buat Akun Lokal & Simpan Lokal
            $db = \Config\Database::connect();
            $roleMahasiswa = $db->table('roles')->where('nama_role', 'Mahasiswa')->get()->getRowArray();
            $roleId = $roleMahasiswa ? $roleMahasiswa['id'] : 3;

            $password = date('Ymd', strtotime($post['tanggal_lahir']));
            
            $userData = [
                'username'      => $post['nim'],
                'email'         => $post['email_pribadi'],
                'password_hash' => password_hash($password, PASSWORD_DEFAULT),
                'role_id'       => $roleId,
                'is_active'     => 1
            ];
            $this->userModel->insert($userData);
            $userId = $this->userModel->getInsertID();

            // Insert to local mahasiswa table
            $mhsData = [
                'id_mahasiswa_pddikti' => $id_mahasiswa_pddikti,
                'id_registrasi_mahasiswa' => $id_registrasi_mahasiswa,
                'user_id' => $userId,
                'prodi_id' => $post['prodi_id'],
                'nim' => $post['nim'],
                'nama_lengkap' => $post['nama_lengkap'],
                'tempat_lahir' => $post['tempat_lahir'],
                'tanggal_lahir' => $post['tanggal_lahir'],
                'jenis_kelamin' => $post['jenis_kelamin'],
                'agama' => match($post['agama']) {
                    '1' => 'Islam', '2' => 'Kristen', '3' => 'Katholik', '4' => 'Hindu', '5' => 'Buddha', '6' => 'Konghucu', default => 'Islam'
                },
                'kewarganegaraan' => 'Indonesia',
                'nik' => $post['nik'],
                'nama_ibu_kandung' => $post['nama_ibu_kandung'],
                'kelurahan' => $post['kelurahan'],
                'kecamatan' => $post['kecamatan'],
                'angkatan' => substr($post['periode_masuk'], 0, 4),
                'status_mahasiswa' => 'Aktif',
                
                // New local fields
                'nisn' => $post['nisn'] ?? null,
                'npwp' => $post['npwp'] ?? null,
                'jalan' => $post['jalan'] ?? null,
                'dusun' => $post['dusun'] ?? null,
                'rt' => $post['rt'] ?? null,
                'rw' => $post['rw'] ?? null,
                'kode_pos' => $post['kode_pos'] ?? null,
                'telepon' => $post['telepon'] ?? null,
                'no_hp' => $post['no_hp'] ?? null,
                'email_pribadi' => $post['email_pribadi'] ?? null,
                'penerima_kps' => $post['penerima_kps'] == 1 ? 'Ya' : 'Tidak',
                
                'nik_ayah' => $post['nik_ayah'] ?? null,
                'nama_ayah' => $post['nama_ayah'] ?? null,
                'tanggal_lahir_ayah' => empty($post['tanggal_lahir_ayah']) ? null : $post['tanggal_lahir_ayah'],
                'pendidikan_ayah' => $post['pendidikan_ayah'],
                'pekerjaan_ayah' => $post['pekerjaan_ayah'],
                'penghasilan_ayah' => $post['penghasilan_ayah'],
                
                'nik_ibu' => $post['nik_ibu'] ?? null,
                'tanggal_lahir_ibu' => empty($post['tanggal_lahir_ibu']) ? null : $post['tanggal_lahir_ibu'],
                'pendidikan_ibu' => $post['pendidikan_ibu'],
                'pekerjaan_ibu' => $post['pekerjaan_ibu'],
                'penghasilan_ibu' => $post['penghasilan_ibu'],
                
                'nama_wali' => $post['nama_wali'] ?? null,
                'tanggal_lahir_wali' => empty($post['tanggal_lahir_wali']) ? null : $post['tanggal_lahir_wali'],
                'pendidikan_wali' => $post['pendidikan_wali'],
                'pekerjaan_wali' => $post['pekerjaan_wali'],
                'penghasilan_wali' => $post['penghasilan_wali'],
                'tanggal_daftar' => $post['tanggal_daftar'] ?? null,
                'pembiayaan_awal' => $post['pembiayaan_awal'] ?? null,
                'biaya_masuk' => $post['biaya_masuk'] ?? null,
                'asal_pt' => $post['asal_pt'] ?? null,
                'asal_prodi' => $post['asal_prodi'] ?? null
            ];
            $this->mahasiswaModel->insert($mhsData);

            if ($riwayatSuccess) {
                session()->setFlashdata('success', 'Berhasil! Mahasiswa baru berhasil ditambahkan secara komprehensif di lokal dan ter-Push ke PDDIKTI.');
            } else {
                session()->setFlashdata('error', 'Berhasil Push Biodata & Simpan Lokal, tapi Gagal Push Riwayat Akademik: ' . $riwayatErrorMsg . '. Harap perbaiki Riwayat Akademik di Admin PDDIKTI.');
            }
            return redirect()->to('/mahasiswa');

        } catch (\Exception $e) {
            session()->setFlashdata('error', 'Terjadi kesalahan sistem: ' . $e->getMessage());
            return redirect()->back()->withInput();
        }
    }

    public function show($id)
    {
        $mhs = $this->mahasiswaModel->select('mahasiswa.*, program_studi.nama_prodi, program_studi.jenjang, users.username')
                                    ->join('program_studi', 'program_studi.id = mahasiswa.prodi_id', 'left')
                                    ->join('users', 'users.id = mahasiswa.user_id', 'left')
                                    ->find($id);
        
        if (!$mhs) {
            session()->setFlashdata('error', 'Mahasiswa tidak ditemukan');
            return redirect()->to('/mahasiswa');
        }

        $data = [
            'title' => 'Detail Mahasiswa - ' . $mhs['nama_lengkap'],
            'mhs'   => $mhs
        ];

        return view('mahasiswa/show', $data);
    }

    public function getBatchStudents()
    {
        // For batch sync, fetch only those who haven't been fully synced yet,
        // or just fetch all active students. Let's fetch all.
        $mhs = $this->mahasiswaModel->select('id')->findAll();
        $ids = array_column($mhs, 'id');
        return $this->response->setJSON(['status' => 'success', 'data' => $ids]);
    }

    public function syncBiodataBatch()
    {
        if (!$this->request->isAJAX()) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Invalid request']);
        }

        $ids = $this->request->getJSON()->ids ?? [];
        if (empty($ids)) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'No IDs provided']);
        }

        $pddiktiUrl = $this->pengaturanModel->getValue('pddikti_url', '');
        $pddiktiUsername = $this->pengaturanModel->getValue('pddikti_username', '');
        $pddiktiPassword = $this->pengaturanModel->getValue('pddikti_password', '');

        $client = \Config\Services::curlrequest();

        // 1. Get Token
        $response = $client->post($pddiktiUrl, [
            'json' => [
                'act'      => 'GetToken',
                'username' => $pddiktiUsername,
                'password' => $pddiktiPassword
            ],
            'verify' => false,
            'timeout' => 30,
            'http_errors' => false
        ]);

        $result = json_decode($response->getBody(), true);
        if (!$result || $result['error_code'] != 0) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Token failed']);
        }

        $token = $result['data']['token'];
        $success = 0;

        foreach ($ids as $id) {
            $mhs = $this->mahasiswaModel->find($id);
            if (!$mhs || empty($mhs['id_mahasiswa_pddikti'])) continue;

            $filter = "id_mahasiswa='" . $mhs['id_mahasiswa_pddikti'] . "'";
            
            $resBio = $client->post($pddiktiUrl, [
                'json' => [
                    'act'    => 'GetBiodataMahasiswa',
                    'token'  => $token,
                    'filter' => $filter,
                    'limit'  => 1
                ],
                'verify' => false,
                'timeout' => 30,
                'http_errors' => false
            ]);

            $resBioData = json_decode($resBio->getBody(), true);
            if ($resBioData && $resBioData['error_code'] == 0 && !empty($resBioData['data'])) {
                $bio = $resBioData['data'][0];
                
                $dataUpdate = [
                    'nik' => $bio['nik'],
                    'tempat_lahir' => $bio['tempat_lahir'],
                    'agama' => $bio['nama_agama'],
                    'kewarganegaraan' => $bio['kewarganegaraan'],
                    'nisn' => $bio['nisn'],
                    'npwp' => $bio['npwp'],
                    'jalan' => $bio['jalan'],
                    'dusun' => $bio['dusun'],
                    'rt' => $bio['rt'],
                    'rw' => $bio['rw'],
                    'kelurahan' => $bio['kelurahan'],
                    'kode_pos' => $bio['kode_pos'],
                    'kecamatan' => $bio['nama_wilayah'],
                    'jenis_tinggal' => $bio['nama_jenis_tinggal'],
                    'telepon' => $bio['telepon'],
                    'no_hp' => $bio['handphone'] ?: $mhs['no_hp'],
                    'email_pribadi' => $bio['email'],
                    'penerima_kps' => $bio['penerima_kps'] == 1 ? 'Ya' : 'Tidak',
                    'nomor_kps' => $bio['nomor_kps'],
                    
                    'nik_ayah' => $bio['nik_ayah'],
                    'nama_ayah' => $bio['nama_ayah'],
                    'tanggal_lahir_ayah' => !empty($bio['tanggal_lahir_ayah']) ? date('Y-m-d', strtotime($bio['tanggal_lahir_ayah'])) : null,
                    'pendidikan_ayah' => $bio['nama_pendidikan_ayah'],
                    'pekerjaan_ayah' => $bio['nama_pekerjaan_ayah'],
                    'penghasilan_ayah' => $bio['nama_penghasilan_ayah'],
                    
                    'nik_ibu' => $bio['nik_ibu'],
                    'nama_ibu_kandung' => $bio['nama_ibu_kandung'],
                    'tanggal_lahir_ibu' => !empty($bio['tanggal_lahir_ibu']) ? date('Y-m-d', strtotime($bio['tanggal_lahir_ibu'])) : null,
                    'pendidikan_ibu' => $bio['nama_pendidikan_ibu'],
                    'pekerjaan_ibu' => $bio['nama_pekerjaan_ibu'],
                    'penghasilan_ibu' => $bio['nama_penghasilan_ibu'],
                    
                    'nama_wali' => $bio['nama_wali'],
                    'tanggal_lahir_wali' => !empty($bio['tanggal_lahir_wali']) ? date('Y-m-d', strtotime($bio['tanggal_lahir_wali'])) : null,
                    'pendidikan_wali' => $bio['nama_pendidikan_wali'],
                    'pekerjaan_wali' => $bio['nama_pekerjaan_wali'],
                    'penghasilan_wali' => $bio['nama_penghasilan_wali']
                ];
                
                $this->mahasiswaModel->update($id, $dataUpdate);
                $success++;
            }
        }

        return $this->response->setJSON(['status' => 'success', 'synced' => $success]);
    }
}
