<div class="space-y-6">
    <div>
        <h1 class="text-xl font-semibold">Dapodik</h1>
        <p class="text-gray-600 dark:text-gray-400 mt-1">Sinkron peserta didik dari Dapodik WebService dan mapping rombel ke kelas internal.</p>
    </div>

    <!-- A) Sync Students -->
    <div class="rounded-2xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-6 shadow-sm">
        <h2 class="font-semibold text-gray-900 dark:text-gray-100 mb-2">Sinkron Siswa</h2>
        <p class="text-sm text-gray-500 dark:text-gray-400 mb-4">Ambil data peserta didik dari Dapodik dan upsert ke data siswa. Rombel yang belum di-map akan tetap unmapped.</p>
        <button type="button" id="btn-sync" class="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg bg-primary text-white font-medium hover:bg-primary-hover transition-colors disabled:opacity-50 disabled:cursor-not-allowed">
            <i class="bx bx-cloud-download text-xl"></i>
            <span id="btn-sync-text">Jalankan Sinkronisasi</span>
        </button>
        <div id="sync-progress" class="mt-4 hidden">
            <div class="flex items-center justify-between text-sm text-gray-600 dark:text-gray-400 mb-2">
                <span id="sync-progress-text">0 / 0 (0%)</span>
            </div>
            <div class="h-2.5 w-full rounded-full bg-gray-200 dark:bg-gray-700 overflow-hidden">
                <div id="sync-progress-bar" class="h-full bg-primary transition-all duration-300 ease-out" style="width: 0%"></div>
            </div>
        </div>
        <div id="sync-result" class="mt-4 hidden">
            <pre id="sync-result-body" class="p-4 rounded-lg bg-gray-100 dark:bg-gray-900 text-sm overflow-auto max-h-64"></pre>
        </div>
    </div>

    <!-- B) Rombel Mapping -->
    <div class="rounded-2xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-6 shadow-sm">
        <div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-4">
            <h2 class="font-semibold text-gray-900 dark:text-gray-100">Mapping Rombel</h2>
            <label class="flex items-center gap-2 cursor-pointer">
                <input type="checkbox" id="filter-unmapped" class="rounded border-gray-300 text-primary focus:ring-primary">
                <span class="text-sm text-gray-700 dark:text-gray-300">Hanya unmapped</span>
            </label>
        </div>
        <div id="mappings-loading" class="py-8 text-center text-gray-500 dark:text-gray-400">Memuat…</div>
        <div id="mappings-error" class="hidden py-4 text-red-600 dark:text-red-400"></div>
        <div id="mappings-content" class="hidden overflow-x-auto">
            <table class="w-full text-left">
                <thead class="bg-gray-50 dark:bg-gray-700/50 text-sm text-gray-600 dark:text-gray-400">
                    <tr>
                        <th class="px-4 py-3 font-medium">Dapodik Rombel</th>
                        <th class="px-4 py-3 font-medium">Kelas (internal)</th>
                        <th class="px-4 py-3 font-medium">Last Seen</th>
                        <th class="px-4 py-3 font-medium text-right">Aksi</th>
                    </tr>
                </thead>
                <tbody id="mappings-tbody" class="divide-y divide-gray-200 dark:divide-gray-700"></tbody>
            </table>
        </div>
    </div>
</div>

<div id="toast-container" class="fixed bottom-6 right-6 z-[60] flex flex-col gap-2 pointer-events-none"></div>

<script>
(function() {
    var baseUrl = '<?= base_url() ?>'.replace(/\/$/, '');
    var apiSync = baseUrl + '/api/academic/dapodik/sync/students';
    var apiStatus = baseUrl + '/api/academic/dapodik/sync/status/';
    var apiRombels = baseUrl + '/api/academic/dapodik/rombels';
    var apiClasses = baseUrl + '/api/academic/classes';

    var btnSync = document.getElementById('btn-sync');
    var btnSyncText = document.getElementById('btn-sync-text');
    var syncProgress = document.getElementById('sync-progress');
    var syncProgressText = document.getElementById('sync-progress-text');
    var syncProgressBar = document.getElementById('sync-progress-bar');
    var syncResult = document.getElementById('sync-result');
    var syncResultBody = document.getElementById('sync-result-body');
    var pollTimer = null;
    var filterUnmapped = document.getElementById('filter-unmapped');
    var mappingsLoading = document.getElementById('mappings-loading');
    var mappingsError = document.getElementById('mappings-error');
    var mappingsContent = document.getElementById('mappings-content');
    var mappingsTbody = document.getElementById('mappings-tbody');
    var toastContainer = document.getElementById('toast-container');
    var classesList = [];

    function showToast(message, type) {
        type = type || 'success';
        var el = document.createElement('div');
        el.className = 'pointer-events-auto px-4 py-3 rounded-lg shadow-lg text-sm font-medium ' + (type === 'success' ? 'bg-green-600 text-white' : 'bg-red-600 text-white');
        el.textContent = message;
        toastContainer.appendChild(el);
        setTimeout(function() { if (el.parentNode) el.parentNode.removeChild(el); }, 4000);
    }

    function escapeHtml(str) { if (str == null) return ''; var d = document.createElement('div'); d.textContent = str; return d.innerHTML; }

    function loadClasses(callback) {
        fetch(apiClasses, { method: 'GET', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' } })
            .then(function(r) { return r.json(); })
            .then(function(res) {
                var list = (res && res.data && res.data.data) ? res.data.data : (Array.isArray(res && res.data) ? res.data : []);
                classesList = list;
                if (callback) callback();
            })
            .catch(function() { if (callback) callback(); });
    }

    function stopPolling() {
        if (pollTimer) {
            clearTimeout(pollTimer);
            pollTimer = null;
        }
        btnSync.disabled = false;
        btnSyncText.textContent = 'Jalankan Sinkronisasi';
    }

    function pollStatus(jobId) {
        fetch(apiStatus + jobId, { method: 'GET', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' } })
            .then(function(r) { return r.json().then(function(j) { return { ok: r.ok, data: j }; }); })
            .then(function(r) {
                var d = r.data && r.data.data ? r.data.data : r.data;
                if (!d) return;
                var total = d.total_rows || 0;
                var processed = d.processed_rows || 0;
                var percent = d.percent || (total > 0 ? Math.round((processed / total) * 100) : 0);
                var status = d.status || 'running';
                syncProgressText.textContent = processed + ' / ' + (total > 0 ? total : '?') + ' (' + percent + '%)';
                syncProgressBar.style.width = Math.min(percent, 100) + '%';
                if (status === 'completed') {
                    stopPolling();
                    syncProgress.classList.add('hidden');
                    showToast('Sinkronisasi selesai');
                    loadMappings();
                } else if (status === 'failed') {
                    stopPolling();
                    syncProgress.classList.add('hidden');
                    showToast(d.message || 'Sinkronisasi gagal', 'error');
                } else {
                    pollTimer = setTimeout(function() { pollStatus(jobId); }, 1000);
                }
            })
            .catch(function() {
                pollTimer = setTimeout(function() { pollStatus(jobId); }, 1000);
            });
    }

    btnSync.addEventListener('click', function() {
        if (btnSync.disabled) return;
        btnSync.disabled = true;
        btnSyncText.textContent = 'Memulai…';
        syncResult.classList.add('hidden');
        syncProgress.classList.add('hidden');
        fetch(apiSync, {
            method: 'POST',
            credentials: 'same-origin',
            headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json', 'Accept': 'application/json' },
            body: JSON.stringify({ limit: 100, max_pages: 50 })
        })
            .then(function(r) { return r.json().then(function(j) { return { ok: r.ok, data: j }; }); })
            .then(function(r) {
                if (!r.ok) {
                    stopPolling();
                    showToast(r.data && r.data.message ? r.data.message : 'Gagal memulai sinkronisasi', 'error');
                    return;
                }
                var d = r.data && r.data.data ? r.data.data : r.data;
                var jobId = d && d.job_id ? d.job_id : null;
                var total = d && d.total_rows != null ? d.total_rows : 0;
                if (!jobId) {
                    stopPolling();
                    showToast('Invalid response', 'error');
                    return;
                }
                btnSyncText.textContent = 'Sinkronisasi berjalan…';
                syncProgress.classList.remove('hidden');
                syncProgressText.textContent = '0 / ' + (total > 0 ? total : '?') + ' (0%)';
                syncProgressBar.style.width = '0%';
                pollStatus(jobId);
            })
            .catch(function() {
                stopPolling();
                showToast('Gagal memulai sinkronisasi', 'error');
            });
    });

    function buildRombelsUrl() {
        var url = apiRombels;
        if (filterUnmapped.checked) url += '?unmapped_only=1';
        return url;
    }

    function loadMappings() {
        mappingsLoading.classList.remove('hidden');
        mappingsError.classList.add('hidden');
        mappingsContent.classList.add('hidden');
        fetch(buildRombelsUrl(), { method: 'GET', credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest', 'Accept': 'application/json' } })
            .then(function(r) { return r.json().then(function(j) { return { ok: r.ok, data: j }; }); })
            .then(function(r) {
                mappingsLoading.classList.add('hidden');
                if (!r.ok) {
                    mappingsError.textContent = r.data && r.data.message ? r.data.message : 'Gagal memuat';
                    mappingsError.classList.remove('hidden');
                    return;
                }
                var list = (r.data && r.data.data) ? r.data.data : (Array.isArray(r.data) ? r.data : []);
                mappingsTbody.innerHTML = '';
                list.forEach(function(row) {
                    var tr = document.createElement('tr');
                    tr.className = 'hover:bg-gray-50 dark:hover:bg-gray-700/30';
                    tr.setAttribute('data-id', row.id);
                    var selectHtml = '<option value="">— Tidak di-map —</option>';
                    classesList.forEach(function(c) {
                        var label = c.full_label || (c.grade + ' ' + (c.major || '') + ' ' + c.name).trim();
                        var sel = row.class_id === c.id ? ' selected' : '';
                        selectHtml += '<option value="' + c.id + '"' + sel + '>' + escapeHtml(label) + '</option>';
                    });
                    var lastSeen = row.last_seen_at ? escapeHtml(row.last_seen_at) : '–';
                    tr.innerHTML =
                        '<td class="px-4 py-3 font-medium">' + escapeHtml(row.dapodik_rombel) + '</td>' +
                        '<td class="px-4 py-3"><select class="mapping-class-select w-full max-w-xs px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" data-id="' + row.id + '">' + selectHtml + '</select></td>' +
                        '<td class="px-4 py-3 text-gray-600 dark:text-gray-400 text-sm">' + lastSeen + '</td>' +
                        '<td class="px-4 py-3 text-right"><button type="button" class="btn-save-mapping px-3 py-1.5 rounded-lg bg-primary text-white text-sm hover:bg-primary-hover" data-id="' + row.id + '">Simpan</button></td>';
                    mappingsTbody.appendChild(tr);
                });
                mappingsTbody.querySelectorAll('.btn-save-mapping').forEach(function(btn) {
                    btn.addEventListener('click', function() {
                        var id = parseInt(btn.getAttribute('data-id'), 10);
                        var row = mappingsTbody.querySelector('tr[data-id="' + id + '"]');
                        var sel = row ? row.querySelector('.mapping-class-select') : null;
                        var classId = sel && sel.value ? parseInt(sel.value, 10) : null;
                        btn.disabled = true;
                        fetch(apiRombels + '/' + id, {
                            method: 'PUT',
                            credentials: 'same-origin',
                            headers: { 'X-Requested-With': 'XMLHttpRequest', 'Content-Type': 'application/json', 'Accept': 'application/json' },
                            body: JSON.stringify({ class_id: classId })
                        })
                            .then(function(res) { return res.json().then(function(j) { return { ok: res.ok, data: j }; }); })
                            .then(function(res) {
                                btn.disabled = false;
                                if (res.ok) showToast('Mapping disimpan');
                                else showToast(res.data && res.data.message ? res.data.message : 'Gagal', 'error');
                            })
                            .catch(function() { btn.disabled = false; showToast('Gagal menyimpan', 'error'); });
                    });
                });
                mappingsContent.classList.remove('hidden');
            })
            .catch(function() {
                mappingsLoading.classList.add('hidden');
                mappingsError.textContent = 'Gagal memuat data';
                mappingsError.classList.remove('hidden');
            });
    }

    filterUnmapped.addEventListener('change', loadMappings);

    loadClasses(function() { loadMappings(); });
})();
</script>
