<!DOCTYPE html>
<html lang="id">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>OCR KTP/KK - Pembaca Dokumen Indonesia</title>
    <link rel="stylesheet" href="/static/style.css">
</head>

<body>
    <div class="container">
        <header>
            <h1>📄 OCR KTP/KK</h1>
            <p class="subtitle">Pembaca Dokumen Indonesia Offline</p>
            <div class="header-actions">
                <button id="reloadBtn" class="archive-header-btn secondary" title="Reload halaman">🔄 Reset /
                    Baru</button>
                <button id="archiveBtn" class="archive-header-btn">📂 Arsip KTP</button>
                <button id="archiveKKBtn" class="archive-header-btn">📂 Arsip KK</button>
            </div>
        </header>

        <main>
            <!-- Upload Section -->
            <section class="upload-section">
                <div class="doc-type-selector">
                    <button class="doc-btn active" data-type="ktp">
                        <span class="icon">🪪</span>
                        KTP
                    </button>
                    <button class="doc-btn" data-type="kk">
                        <span class="icon">👨‍👩‍👧‍👦</span>
                        Kartu Keluarga
                    </button>
                </div>

                <div class="dropzone" id="dropzone">
                    <div class="dropzone-content">
                        <div class="upload-icon">📷</div>
                        <p>Drag & drop gambar di sini</p>
                        <p class="hint">atau</p>
                        <label class="file-btn">
                            Pilih File
                            <input type="file" id="fileInput" accept="image/*" hidden>
                        </label>
                        <p class="file-types">PNG, JPG, JPEG, BMP, WEBP (max 16MB)</p>
                    </div>

                    <!-- Crop Container -->
                    <div id="cropContainer" class="crop-container" style="display: none;">
                        <!-- Canvas for editing (rotation & crop) -->
                        <canvas id="cropCanvas" class="preview-image"></canvas>
                        <!-- Keep img for simple viewing if needed, or just use canvas. Let's rely on canvas for editor -->
                        <img id="preview" class="preview-image" style="display: none;">

                        <div id="cropArea" class="crop-area">
                            <svg width="100%" height="100%"
                                style="position: absolute; top:0; left:0; overflow:visible;">
                                <polygon id="cropPolygon" points=""
                                    style="fill: rgba(255, 255, 255, 0.1); stroke: var(--accent-primary); stroke-width: 2; vector-effect: non-scaling-stroke;">
                                </polygon>
                            </svg>
                            <!-- Handles TL, TR, BR, BL -->
                            <div class="crop-handle" data-index="0"></div>
                            <div class="crop-handle" data-index="1"></div>
                            <div class="crop-handle" data-index="2"></div>
                            <div class="crop-handle" data-index="3"></div>
                        </div>
                    </div>
                </div>

                <!-- Crop Actions -->
                <div id="cropActions" class="crop-actions-container" style="display: none;">
                    <div class="rotation-control">
                        <label for="rotationSlider">Rotasi: <span id="rotationValue">0°</span></label>
                        <input type="range" id="rotationSlider" min="-45" max="45" value="0" step="1">
                    </div>

                    <div class="crop-buttons">
                        <button type="button" id="resetCropBtn" class="crop-action-btn secondary">🔄 Reset</button>
                        <button type="button" id="applyCropBtn" class="crop-action-btn primary">✂️ Terapkan
                            Crop</button>
                    </div>
                </div>

                <button id="processBtn" class="process-btn" disabled>
                    <span class="btn-text">🔍 Proses OCR</span>
                    <span class="btn-loading" style="display: none;">⏳ Memproses...</span>
                </button>
            </section>

            <!-- Results Section -->
            <section class="results-section" id="resultsSection" style="display: none;">
                <div class="results-header">
                    <h2>📋 Hasil Ekstraksi</h2>
                    <div class="results-actions">
                        <button class="action-btn secondary" id="printBtn">🖨️ Cetak</button>
                        <button class="action-btn secondary" id="downloadBtn">⬇️ Unduh</button>
                        <button class="action-btn primary" id="saveBtn" title="Simpan KTP">💾 Simpan</button>
                        <button class="action-btn" id="copyBtn" title="Copy Text (Word)">📋 Copy</button>
                        <button class="action-btn" id="exportBtn" title="Download Excel (.xlsx)">📤 Excel</button>
                        <button class="action-btn secondary" id="toggleRaw">📝 Raw Text</button>
                    </div>
                </div>

                <div class="results-content">
                    <table class="results-table" id="resultsTable">
                        <thead>
                            <tr>
                                <th>Field</th>
                                <th>Nilai</th>
                            </tr>
                        </thead>
                        <tbody id="resultsBody">
                        </tbody>
                    </table>

                    <div class="raw-text-section" id="rawTextSection" style="display: none;">
                        <h3>Raw OCR Text</h3>
                        <pre id="rawText"></pre>
                    </div>
                </div>
            </section>

            <!-- Error Section -->
            <section class="error-section" id="errorSection" style="display: none;">
                <div class="error-content">
                    <span class="error-icon">⚠️</span>
                    <p id="errorMessage"></p>
                </div>
            </section>
        </main>

        <!-- Login Modal -->
        <div id="loginModal" class="modal" style="display: none;">
            <div class="modal-content" style="max-width: 400px;">
                <div class="modal-header">
                    <h2>🔐 Login Arsip</h2>
                    <span class="close-btn" id="closeLoginBtn">&times;</span>
                </div>
                <div class="modal-body">
                    <p style="margin-bottom:1rem; color:var(--text-secondary);">Masukkan password untuk mengakses arsip
                        (Default: admin / 123).</p>
                    <div class="form-group">
                        <label>Username</label>
                        <input type="text" id="loginUser" class="form-control" value="admin">
                    </div>
                    <div class="form-group">
                        <label>Password</label>
                        <input type="password" id="loginPass" class="form-control" placeholder="Password">
                    </div>
                    <div id="loginError"
                        style="color:var(--text-error); display:none; margin-bottom:1rem; font-size:0.9rem;"></div>
                    <button id="submitLoginBtn" class="action-btn primary" style="width:100%;">Masuk</button>
                </div>
            </div>
        </div>

        <!-- Archive Modal -->
        <div id="archiveModal" class="modal" style="display: none;">
            <div class="modal-content">
                <div class="modal-header">
                    <h2>📂 Arsip KTP</h2>
                    <button id="closeModalBtn" class="close-btn">&times;</button>
                </div>
                <div class="modal-body">
                    <div id="archiveList" class="archive-list">
                        <!-- Cards will be loaded here -->
                    </div>
                    <div id="archiveLoading" class="archive-loading" style="display: none;">
                        ⏳ Memuat...
                    </div>
                    <div id="archiveEmpty" class="archive-empty" style="display: none;">
                        Belum ada KTP yang disimpan
                    </div>
                </div>
            </div>
        </div>

        <!-- Print Settings Modal -->
        <div id="printSettingsModal" class="modal" style="display: none;">
            <div class="modal-content" style="max-width: 500px;">
                <div class="modal-header">
                    <h2>🖨️ Pengaturan Cetak</h2>
                    <span class="close-btn" id="closePrintBtn">&times;</span>
                </div>
                <div class="modal-body">
                    <div class="form-group">
                        <label>Jumlah Salinan (Copies)</label>
                        <input type="number" id="printCopies" class="form-control" value="1" min="1" max="50">
                        <p class="suggestion-text">Masukkan jumlah KTP yang ingin dicetak dalam satu halaman.</p>
                    </div>
                    <div class="form-group" style="margin-top: 1rem;">
                        <label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
                            <input type="checkbox" id="printAutoArrange" checked>
                            <span>Atur Otomatis (Hemat Kertas)</span>
                        </label>
                        <p class="suggestion-text">Otomatis menata gambar berderet untuk memaksimalkan ruang kertas A4.
                        </p>
                    </div>

                    <div class="print-preview-info"
                        style="margin-top: 1.5rem; padding: 1rem; background: var(--bg-primary); border-radius: var(--radius);">
                        <p>ℹ️ <strong>Tips:</strong> Saat dialog print muncul:</p>
                        <ul style="margin-left: 1.5rem; margin-top: 0.5rem; color: var(--text-secondary);">
                            <li>Pilih Paper Size: <strong>A4</strong></li>
                            <li>Margins: <strong>Minimum / None</strong></li>
                            <li>Scale: <strong>100%</strong></li>
                        </ul>
                    </div>

                    <div style="margin-top: 2rem; display: flex; gap: 1rem;">
                        <button id="cancelPrintBtn" class="action-btn secondary" style="flex: 1;">Batal</button>
                        <button id="confirmPrintBtn" class="action-btn primary" style="flex: 1;">🖨️ Cetak
                            Sekarang</button>
                    </div>
                </div>
            </div>
        </div>



        <footer>
            <p>OCR menggunakan <a href="https://github.com/PaddlePaddle/PaddleOCR" target="_blank">PaddleOCR</a> • Data
                diproses secara lokal</p>
            <p style="margin-top: 0.5rem; font-size: 0.9em; opacity: 0.8;">&copy; Copyright by Wartana</p>
        </footer>
    </div>

    <script>
        // State
        let selectedFile = null;
        let originalImageObject = null; // For cropping
        let extractedData = null;
        let currentDocType = 'ktp'; // Default
        let currentArchiveType = 'ktp'; // Default for archive view

        // Elements
        const dropzone = document.getElementById('dropzone');
        const fileInput = document.getElementById('fileInput');
        const preview = document.getElementById('preview');
        const processBtn = document.getElementById('processBtn');
        const resultsSection = document.getElementById('resultsSection');
        const resultsBody = document.getElementById('resultsBody');
        const rawText = document.getElementById('rawText');
        const rawTextSection = document.getElementById('rawTextSection');
        const errorSection = document.getElementById('errorSection');
        const errorMessage = document.getElementById('errorMessage');
        const docBtns = document.querySelectorAll('.doc-btn');

        // Field labels untuk display
        const fieldLabels = {
            // KTP
            'nik': 'NIK',
            'nama': 'Nama',
            'tempat_lahir': 'Tempat Lahir',
            'tanggal_lahir': 'Tanggal Lahir',
            'jenis_kelamin': 'Jenis Kelamin',
            'gol_darah': 'Gol. Darah',
            'alamat': 'Alamat',
            'rt_rw': 'RT/RW',
            'kel_desa': 'Kel/Desa',
            'kecamatan': 'Kecamatan',
            'agama': 'Agama',
            'status_perkawinan': 'Status Perkawinan',
            'pekerjaan': 'Pekerjaan',
            'kewarganegaraan': 'Kewarganegaraan',
            'berlaku_hingga': 'Berlaku Hingga',
            'provinsi': 'Provinsi',
            'kabupaten_kota': 'Kabupaten/Kota',
            'tanggal_penerbitan': 'Tanggal Penerbitan',
            // KK
            'no_kk': 'No. KK',
            'nama_kepala_keluarga': 'Kepala Keluarga',
            'kode_pos': 'Kode Pos',
            'anggota_keluarga': 'Jumlah Anggota'
        };

        // Doc type selection
        docBtns.forEach(btn => {
            btn.addEventListener('click', () => {
                docBtns.forEach(b => b.classList.remove('active'));
                btn.classList.add('active');
                currentDocType = btn.dataset.type;
            });
        });

        // Drag & drop
        dropzone.addEventListener('dragover', (e) => {
            e.preventDefault();
            dropzone.classList.add('dragover');
        });

        dropzone.addEventListener('dragleave', () => {
            dropzone.classList.remove('dragover');
        });

        dropzone.addEventListener('drop', (e) => {
            e.preventDefault();
            dropzone.classList.remove('dragover');
            const files = e.dataTransfer.files;
            if (files.length > 0) {
                handleFile(files[0]);
            }
        });

        // File input
        fileInput.addEventListener('change', (e) => {
            if (e.target.files.length > 0) {
                handleFile(e.target.files[0]);
            }
        });

        // Click on dropzone
        // Click on dropzone - DISABLED (User request: Only 'Pilih File' button should work)
        dropzone.addEventListener('click', (e) => {
            // Do nothing. Label 'file-btn' handles clicks on itself automatically.
            // preventing accidental uploads when clicking background/crop area.
        });

        // Canvas & Rotation Variables
        const cropCanvas = document.getElementById('cropCanvas');
        const rotationSlider = document.getElementById('rotationSlider');
        const rotationValue = document.getElementById('rotationValue');

        let currentRotation = 0;
        // let originalImageObject = null; // Store Image object for redraws - moved to global state

        function handleFile(file) {
            if (!file.type.startsWith('image/')) {
                showError('File harus berupa gambar');
                return;
            }

            if (file.size > 16 * 1024 * 1024) {
                showError('Ukuran file maksimal 16MB');
                return;
            }

            originalFile = file;
            selectedFile = file;
            currentRotation = 0;
            updateRotationUI();

            // Load image
            const reader = new FileReader();
            reader.onload = (e) => {
                originalImageData = e.target.result;

                // Create Image object
                const img = new Image();
                img.onload = () => {
                    originalImageObject = img;
                    preview.src = e.target.result; // Keep this for backup/debugging

                    // Render to canvas
                    renderEditor();

                    cropCanvas.style.display = 'block';
                    preview.style.display = 'none';
                    cropContainer.style.display = 'block';
                    dropzone.querySelector('.dropzone-content').style.display = 'none';
                    cropActions.style.display = 'flex';

                    // Init crop area after first render
                    // Small timeout to ensure layout is done
                    setTimeout(initCropArea, 50);
                };
                img.src = e.target.result;
            };
            reader.readAsDataURL(file);

            processBtn.disabled = false;
            hideError();
            resultsSection.style.display = 'none';
        }

        // Handle Rotation
        rotationSlider.addEventListener('input', (e) => {
            currentRotation = parseInt(e.target.value);
            updateRotationUI();
            renderEditor();
        });

        function updateRotationUI() {
            rotationSlider.value = currentRotation;
            rotationValue.textContent = currentRotation + '°';
        }

        function renderEditor() {
            if (!originalImageObject) return;

            const angleRad = currentRotation * Math.PI / 180;
            const sin = Math.abs(Math.sin(angleRad));
            const cos = Math.abs(Math.cos(angleRad));

            // Calculate new bounding box size
            const width = originalImageObject.naturalWidth;
            const height = originalImageObject.naturalHeight;
            const newWidth = width * cos + height * sin;
            const newHeight = width * sin + height * cos;

            // Set canvas internal size
            cropCanvas.width = newWidth;
            cropCanvas.height = newHeight;

            const ctx = cropCanvas.getContext('2d');

            // Clear & Draw
            ctx.clearRect(0, 0, newWidth, newHeight);
            ctx.save();
            ctx.translate(newWidth / 2, newHeight / 2);
            ctx.rotate(angleRad);
            ctx.drawImage(originalImageObject, -width / 2, -height / 2);
            ctx.restore();
        }

        // Crop functionality (Perspective / 4-Point)
        const cropContainer = document.getElementById('cropContainer');

        // Prevent clicks in crop area from triggering file upload
        cropContainer.addEventListener('click', (e) => {
            e.stopPropagation();
        });
        cropContainer.addEventListener('mousedown', (e) => {
            e.stopPropagation();
        });

        const cropArea = document.getElementById('cropArea');
        const cropPolygon = document.getElementById('cropPolygon');
        const cropActions = document.getElementById('cropActions');
        const resetCropBtn = document.getElementById('resetCropBtn');
        const applyCropBtn = document.getElementById('applyCropBtn');

        let originalFile = null;
        let originalImageData = null;
        let cropPoints = []; // [{x,y}, {x,y}, {x,y}, {x,y}]
        let isDragging = false;
        let activeHandleIndex = null;

        // KTP aspect ratio: 85.6mm x 53.98mm = ~1.586
        const KTP_ASPECT_RATIO = 85.6 / 53.98;
        // KK aspect ratio (A4 Landscape): 297mm x 210mm = ~1.414
        const KK_ASPECT_RATIO = 297 / 210;

        function initCropArea() {
            // Match cropArea size/pos to canvas size/pos
            cropArea.style.left = cropCanvas.offsetLeft + 'px';
            cropArea.style.top = cropCanvas.offsetTop + 'px';
            cropArea.style.width = cropCanvas.offsetWidth + 'px';
            cropArea.style.height = cropCanvas.offsetHeight + 'px';

            const w = cropCanvas.offsetWidth;
            const h = cropCanvas.offsetHeight;

            // Initialize default box (Centered Rectangle with appropriate ratio)
            const targetRatio = currentDocType === 'kk' ? KK_ASPECT_RATIO : KTP_ASPECT_RATIO;

            let boxW, boxH;
            if (w / h > targetRatio) {
                boxH = h * 0.7;
                boxW = boxH * targetRatio;
            } else {
                boxW = w * 0.7;
                boxH = boxW / targetRatio;
            }

            const cx = w / 2;
            const cy = h / 2;

            // 0: TL, 1: TR, 2: BR, 3: BL
            cropPoints = [
                { x: cx - boxW / 2, y: cy - boxH / 2 },
                { x: cx + boxW / 2, y: cy - boxH / 2 },
                { x: cx + boxW / 2, y: cy + boxH / 2 },
                { x: cx - boxW / 2, y: cy + boxH / 2 }
            ];

            updateCropVisuals();
            cropArea.style.display = 'block';
        }

        function updateCropVisuals() {
            // Update Handles
            const handles = cropArea.querySelectorAll('.crop-handle');
            cropPoints.forEach((p, i) => {
                if (handles[i]) {
                    handles[i].style.left = p.x + 'px';
                    handles[i].style.top = p.y + 'px';
                }
            });

            // Update Polygon
            // SVG points format: x1,y1 x2,y2 ...
            const pointsStr = cropPoints.map(p => `${p.x},${p.y}`).join(' ');
            cropPolygon.setAttribute('points', pointsStr);
        }

        // Handle Dragging
        const handles = cropArea.querySelectorAll('.crop-handle');
        handles.forEach(handle => {
            handle.addEventListener('mousedown', (e) => {
                e.stopPropagation();
                activeHandleIndex = parseInt(handle.dataset.index);
                isDragging = true;
            });
            handle.addEventListener('touchstart', (e) => {
                e.stopPropagation();
                activeHandleIndex = parseInt(handle.dataset.index);
                isDragging = true;
            }, { passive: false });
        });

        document.addEventListener('mousemove', handleDragMove);
        document.addEventListener('touchmove', handleDragMove, { passive: false });
        document.addEventListener('mouseup', handleDragEnd);
        document.addEventListener('touchend', handleDragEnd);

        // Also allow updating cropArea size on window resize (since canvas might resize)
        window.addEventListener('resize', () => {
            if (cropCanvas.offsetParent) {
                cropArea.style.left = cropCanvas.offsetLeft + 'px';
                cropArea.style.top = cropCanvas.offsetTop + 'px';
                cropArea.style.width = cropCanvas.offsetWidth + 'px';
                cropArea.style.height = cropCanvas.offsetHeight + 'px';
            }
        });

        function getEventPos(e) {
            const rect = cropArea.getBoundingClientRect();
            let clientX, clientY;

            if (e.touches && e.touches.length > 0) {
                clientX = e.touches[0].clientX;
                clientY = e.touches[0].clientY;
            } else {
                clientX = e.clientX;
                clientY = e.clientY;
            }

            return {
                x: clientX - rect.left,
                y: clientY - rect.top
            };
        }

        function handleDragMove(e) {
            if (!isDragging || activeHandleIndex === null) return;
            e.preventDefault();

            const pos = getEventPos(e);

            // Constrain to bounds
            // Allow slightly outside? No, keep inside for UI sanity
            const x = Math.max(0, Math.min(pos.x, cropArea.offsetWidth));
            const y = Math.max(0, Math.min(pos.y, cropArea.offsetHeight));

            cropPoints[activeHandleIndex] = { x, y };
            updateCropVisuals();
        }

        function handleDragEnd() {
            isDragging = false;
            activeHandleIndex = null;
        }

        // Hook rotation to reset crop
        rotationSlider.addEventListener('input', () => {
            // We need to re-init crop area because canvas content changed
            initCropArea();
        });

        // Reset crop button
        resetCropBtn.addEventListener('click', () => {
            currentRotation = 0;
            updateRotationUI();

            if (originalImageObject) {
                renderEditor();
                cropCanvas.style.display = 'block';
                preview.style.display = 'none';
                setTimeout(initCropArea, 50);
                selectedFile = originalFile;
            }
        });

        // Apply crop button (Perspective Transform API)
        applyCropBtn.addEventListener('click', async () => {
            if (!originalImageObject) return;

            applyCropBtn.disabled = true;
            applyCropBtn.textContent = '⏳ Memproses...';

            try {
                // 1. Get current Canvas blob (Rotated image)
                const canvasBlob = await new Promise(resolve => cropCanvas.toBlob(resolve, 'image/jpeg', 0.95));

                // 2. Calculate points relative to internal canvas resolution
                const scaleX = cropCanvas.width / cropCanvas.offsetWidth;
                const scaleY = cropCanvas.height / cropCanvas.offsetHeight;

                // Map points to actual image coordinates
                // Note: The backend expects [TL, TR, BR, BL] which is how cropPoints is ordered [0,1,2,3]
                const realPoints = cropPoints.map(p => [p.x * scaleX, p.y * scaleY]);

                // 3. Send to server
                const formData = new FormData();
                formData.append('image', canvasBlob, 'rotated_temp.jpg');
                formData.append('image', canvasBlob, 'rotated_temp.jpg');
                formData.append('points', JSON.stringify(realPoints));
                formData.append('doc_type', currentDocType);

                const response = await fetch('/api/transform-perspective', {
                    method: 'POST',
                    body: formData
                });

                const result = await response.json();

                if (result.success) {
                    // Update preview with transformed image
                    preview.src = result.image_url;
                    preview.style.display = 'block';
                    cropCanvas.style.display = 'none';
                    cropArea.style.display = 'none';

                    // Fetch blob to update selectedFile
                    const resBlob = await fetch(result.image_url).then(r => r.blob());
                    selectedFile = new File([resBlob], result.filename || 'perspective_cropped.jpg', { type: 'image/jpeg' });

                } else {
                    showError('Gagal transformasi: ' + result.error);
                }

            } catch (error) {
                console.error('Crop error:', error);
                showError('Gagal memproses crop: ' + error.message);
            } finally {
                applyCropBtn.disabled = false;
                applyCropBtn.textContent = '✂️ Terapkan Crop';
            }
        });

        // Process button
        processBtn.addEventListener('click', async () => {
            if (!selectedFile) return;

            const btnText = processBtn.querySelector('.btn-text');
            const btnLoading = processBtn.querySelector('.btn-loading');

            processBtn.disabled = true;
            btnText.style.display = 'none';
            btnLoading.style.display = 'inline';

            try {
                const formData = new FormData();
                formData.append('file', selectedFile);
                formData.append('doc_type', currentDocType);

                const response = await fetch('/upload', {
                    method: 'POST',
                    body: formData
                });

                const result = await response.json();

                if (result.success) {
                    extractedData = result.data;
                    currentDocType = result.doc_type || 'ktp';
                    if (result.validation) {
                        validationResult = result.validation;
                    }
                    displayResults(result);
                    hideError();
                } else {
                    showError(result.error);
                    resultsSection.style.display = 'none';
                }
            } catch (error) {
                showError('Terjadi kesalahan: ' + error.message);
            } finally {
                processBtn.disabled = false;
                btnText.style.display = 'inline';
                btnLoading.style.display = 'none';
            }
        });

        // Region fields that use dropdowns - in hierarchical order
        const regionFields = ['provinsi', 'kabupaten_kota', 'kecamatan', 'kel_desa'];
        let regionData = {
            provinces: [],
            regencies: {},
            districts: {},
            villages: {}
        };
        let validationResult = null;

        // Define field display order
        const fieldOrder = [
            // Location hierarchy first
            'provinsi', 'kabupaten_kota', 'kecamatan', 'kel_desa',
            // Identity
            'nik', 'nama', 'tempat_lahir', 'tanggal_lahir', 'jenis_kelamin', 'gol_darah',
            // Address
            'alamat', 'rt_rw',
            // Other info
            'agama', 'status_perkawinan', 'pekerjaan', 'kewarganegaraan', 'berlaku_hingga',
            // Issue date
            'tanggal_penerbitan',
            // KK specific
            'no_kk', 'nama_kepala_keluarga', 'kode_pos', 'anggota_keluarga'
        ];

        async function displayResults(result) {
            resultsBody.innerHTML = '';
            const data = result.data;
            extractedData = data;

            // Validate region data first
            await validateRegionData(data);

            // Sort keys by fieldOrder
            const sortedKeys = Object.keys(data).sort((a, b) => {
                const indexA = fieldOrder.indexOf(a);
                const indexB = fieldOrder.indexOf(b);
                if (indexA === -1 && indexB === -1) return 0;
                if (indexA === -1) return 1;
                if (indexB === -1) return -1;
                return indexA - indexB;
            });

            // Disable Save button initially (since it's auto-saved)
            const saveBtn = document.getElementById('saveBtn');
            if (result.saved_to_db) {
                saveBtn.disabled = true;
                saveBtn.textContent = '💾 Tersimpan';
                saveBtn.classList.add('secondary');
                saveBtn.classList.remove('primary');
            } else {
                saveBtn.disabled = false;
                saveBtn.textContent = '💾 Simpan';
                saveBtn.classList.remove('secondary');
                saveBtn.classList.add('primary');
            }

            for (const key of sortedKeys) {
                const value = data[key];
                if (key === 'anggota_keluarga') {
                    const count = Array.isArray(value) ? value.length : 0;
                    addResultRow('Jumlah Anggota', count + ' orang', null, false);
                } else if (regionFields.includes(key)) {
                    // Region field with dropdown
                    const label = fieldLabels[key] || key;
                    await addRegionRow(label, value || '', key);
                } else {
                    const label = fieldLabels[key] || key;
                    addResultRow(label, value || '', key, true);
                }
            }

            // Add change listener to all inputs to re-enable save button
            document.querySelectorAll('.editable-field').forEach(input => {
                input.addEventListener('input', enableSaveButton);
            });

            rawText.textContent = result.raw_text;
            resultsSection.style.display = 'block';
            resultsSection.scrollIntoView({ behavior: 'smooth' });
        }

        function enableSaveButton() {
            const saveBtn = document.getElementById('saveBtn');
            saveBtn.disabled = false;
            saveBtn.textContent = '💾 Simpan Perubahan';
            saveBtn.classList.remove('secondary');
            saveBtn.classList.add('primary');
        }

        async function validateRegionData(data) {
            try {
                const response = await fetch('/api/validate-region', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(data)
                });
                const result = await response.json();
                if (result.success) {
                    validationResult = result.validation;
                }
            } catch (e) {
                console.error('Validation error:', e);
            }
        }

        async function addRegionRow(label, value, key) {
            const row = document.createElement('tr');
            const validation = validationResult?.[key];
            const isValid = validation?.valid;
            const suggestion = validation?.suggestion;

            // Status indicator
            const statusIcon = isValid ? '✓' : (value ? '⚠' : '');
            const statusClass = isValid ? 'valid-field' : (value ? 'invalid-field' : '');

            row.innerHTML = `
                <td class="field-label">
                    ${label}
                    <span class="validation-status ${statusClass}">${statusIcon}</span>
                </td>
                <td class="field-value">
                    <div class="region-field-wrapper">
                        <input type="text" class="editable-field ${statusClass}" data-key="${key}" 
                               value="${suggestion || value || ''}" placeholder="Ketik atau pilih...">
                        <select class="region-dropdown" data-key="${key}" style="display: none;">
                            <option value="">-- Pilih --</option>
                        </select>
                        <button type="button" class="dropdown-toggle" data-key="${key}" title="Pilih dari daftar">▼</button>
                    </div>
                    ${suggestion && suggestion !== value ? `<div class="suggestion-text">Saran: ${suggestion}</div>` : ''}
                </td>
            `;

            const input = row.querySelector('input');
            const select = row.querySelector('select');
            const toggleBtn = row.querySelector('.dropdown-toggle');

            // Input change
            input.addEventListener('input', (e) => {
                if (extractedData) {
                    extractedData[key] = e.target.value;
                }
            });

            // Toggle dropdown
            toggleBtn.addEventListener('click', async () => {
                if (select.style.display === 'none') {
                    await loadDropdownOptions(key, select);
                    select.style.display = 'block';
                    input.style.display = 'none';
                } else {
                    select.style.display = 'none';
                    input.style.display = 'block';
                }
            });

            // Select change
            select.addEventListener('change', (e) => {
                const selectedOption = e.target.options[e.target.selectedIndex];
                const selectedCode = selectedOption.value;
                const selectedName = selectedOption.text !== '-- Pilih --' ? selectedOption.text : '';

                input.value = selectedName;
                if (extractedData) {
                    extractedData[key] = selectedName;
                }

                // Update validation result with selected code for cascading
                if (!validationResult) validationResult = {};
                validationResult[key] = {
                    valid: !!selectedCode,
                    code: selectedCode,
                    suggestion: selectedName
                };

                select.style.display = 'none';
                input.style.display = 'block';

                // Change toggle button to checkmark if valid selection
                if (selectedCode) {
                    toggleBtn.textContent = '✓';
                    toggleBtn.classList.add('confirmed');
                    input.classList.remove('invalid-field');
                    input.classList.add('valid-field');
                } else {
                    toggleBtn.textContent = '▼';
                    toggleBtn.classList.remove('confirmed');
                }

                // Clear dependent fields and their codes
                clearDependentFields(key);
            });

            resultsBody.appendChild(row);
        }

        async function loadDropdownOptions(key, select) {
            select.innerHTML = '<option value="">Loading...</option>';

            try {
                let data = [];

                if (key === 'provinsi') {
                    if (!regionData.provinces.length) {
                        const res = await fetch('/api/provinces');
                        const json = await res.json();
                        regionData.provinces = json.data || [];
                    }
                    data = regionData.provinces;
                } else if (key === 'kabupaten_kota') {
                    const provCode = validationResult?.provinsi?.code;
                    if (provCode) {
                        if (!regionData.regencies[provCode]) {
                            const res = await fetch(`/api/regencies/${provCode}`);
                            const json = await res.json();
                            regionData.regencies[provCode] = json.data || [];
                        }
                        data = regionData.regencies[provCode];
                    }
                } else if (key === 'kecamatan') {
                    const regCode = validationResult?.kabupaten_kota?.code;
                    if (regCode) {
                        if (!regionData.districts[regCode]) {
                            const res = await fetch(`/api/districts/${regCode}`);
                            const json = await res.json();
                            regionData.districts[regCode] = json.data || [];
                        }
                        data = regionData.districts[regCode];
                    }
                } else if (key === 'kel_desa') {
                    const distCode = validationResult?.kecamatan?.code;
                    if (distCode) {
                        if (!regionData.villages[distCode]) {
                            const res = await fetch(`/api/villages/${distCode}`);
                            const json = await res.json();
                            regionData.villages[distCode] = json.data || [];
                        }
                        data = regionData.villages[distCode];
                    }
                }

                select.innerHTML = '<option value="">-- Pilih --</option>';
                data.forEach(item => {
                    const option = document.createElement('option');
                    option.value = item.code;
                    option.textContent = item.name;
                    select.appendChild(option);
                });
            } catch (e) {
                select.innerHTML = '<option value="">Error loading data</option>';
            }
        }

        function clearDependentFields(key) {
            const dependents = {
                'provinsi': ['kabupaten_kota', 'kecamatan', 'kel_desa'],
                'kabupaten_kota': ['kecamatan', 'kel_desa'],
                'kecamatan': ['kel_desa']
            };

            (dependents[key] || []).forEach(depKey => {
                const input = document.querySelector(`input[data-key="${depKey}"]`);
                if (input) input.value = '';
                if (extractedData) extractedData[depKey] = '';
                // Clear validation code for cascading
                if (validationResult && validationResult[depKey]) {
                    validationResult[depKey] = { valid: false, code: null, suggestion: null };
                }
            });
        }

        function addResultRow(label, value, key, editable = true) {
            const row = document.createElement('tr');
            if (editable && key) {
                row.innerHTML = `
                    <td class="field-label">${label}</td>
                    <td class="field-value">
                        <input type="text" class="editable-field" data-key="${key}" value="${value || ''}" placeholder="Klik untuk edit...">
                    </td>
                `;
                const input = row.querySelector('input');
                input.addEventListener('input', (e) => {
                    if (extractedData && key) {
                        extractedData[key] = e.target.value;
                    }
                });
            } else {
                row.innerHTML = `
                    <td class="field-label">${label}</td>
                    <td class="field-value">${value || '-'}</td>
                `;
            }
            resultsBody.appendChild(row);
        }

        // Toggle raw text
        document.getElementById('toggleRaw').addEventListener('click', () => {
            const isVisible = rawTextSection.style.display !== 'none';
            rawTextSection.style.display = isVisible ? 'none' : 'block';
        });

        // Copy to clipboard (Formatted Text for Word)
        document.getElementById('copyBtn').addEventListener('click', () => {
            if (extractedData) {
                // Format as Key: Value text
                const excludeKeys = ['raw_text', 'image_path', 'id', 'created_at', 'updated_at'];
                const text = Object.entries(extractedData)
                    .filter(([k, v]) => !excludeKeys.includes(k) && v)
                    .map(([k, v]) => {
                        const label = k.replace(/_/g, ' ').toUpperCase();
                        return `${label}: ${v}`;
                    })
                    .join('\n');

                navigator.clipboard.writeText(text)
                    .then(() => alert('Data berhasil disalin (Format Teks)! Bisa dipaste di Word/Notepad.'));
            }
        });

        // Export Excel (Real .xlsx via Backend)
        document.getElementById('exportBtn').addEventListener('click', async () => {
            if (!extractedData) return;

            const btn = document.getElementById('exportBtn');
            const originalText = btn.innerHTML;
            btn.innerHTML = '⏳...';
            btn.disabled = true;

            try {
                const res = await fetch('/api/export-excel', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(extractedData)
                });

                if (res.ok) {
                    const blob = await res.blob();
                    const url = window.URL.createObjectURL(blob);
                    const a = document.createElement('a');
                    a.href = url;
                    const filename = extractedData.nik ? `Data_KTP_${extractedData.nik}.xlsx` : 'Data_KTP.xlsx';
                    a.download = filename;
                    document.body.appendChild(a);
                    a.click();
                    document.body.removeChild(a);
                    window.URL.revokeObjectURL(url);
                } else {
                    const err = await res.json();
                    alert('Gagal export excel: ' + (err.error || 'Unknown error'));
                }
            } catch (e) {
                console.error(e);
                alert('Error export excel.');
            } finally {
                btn.innerHTML = originalText;
                btn.disabled = false;
            }
        });

        function showError(message) {
            errorMessage.textContent = message;
            errorSection.style.display = 'block';
        }

        function hideError() {
            errorSection.style.display = 'none';
        }

        // Save KTP Button
        const saveBtn = document.getElementById('saveBtn');
        saveBtn.addEventListener('click', async () => {
            if (!extractedData || !selectedFile) return;

            saveBtn.disabled = true;
            saveBtn.innerHTML = '⏳ Menyimpan...';

            // Determine endpoint based on currentDocType
            const endpoint = currentDocType === 'kk' ? '/api/save-kk' : '/api/save-ktp';

            try {
                // Use selectedFile directly (it is already cropped/rotated by Apply Crop)
                const formData = new FormData();
                // Rename file based on type just for neatness
                const filename = currentDocType === 'kk' ? 'kk_saved.jpg' : 'ktp_saved.jpg';
                formData.append('image', selectedFile, filename);
                formData.append('data', JSON.stringify(extractedData));

                // Send to server
                const response = await fetch(endpoint, {
                    method: 'POST',
                    body: formData
                });

                const result = await response.json();

                if (result.success) {
                    const docName = currentDocType === 'kk' ? 'Kartu Keluarga' : 'KTP';
                    alert(`Data ${docName} berhasil disimpan!`);
                    saveBtn.innerHTML = '✅ Tersimpan';
                } else {
                    alert('Gagal menyimpan: ' + result.error);
                    saveBtn.innerHTML = '💾 Simpan';
                    saveBtn.disabled = false;
                }
            } catch (error) {
                alert('Terjadi kesalahan: ' + error.message);
                saveBtn.innerHTML = '💾 Simpan';
                saveBtn.disabled = false;
            }
        });

        // Print functionality
        const printBtn = document.getElementById('printBtn');
        const printSettingsModal = document.getElementById('printSettingsModal');
        const closePrintBtn = document.getElementById('closePrintBtn');
        const cancelPrintBtn = document.getElementById('cancelPrintBtn');
        const confirmPrintBtn = document.getElementById('confirmPrintBtn');
        const printCopiesInput = document.getElementById('printCopies');
        const printAutoArrange = document.getElementById('printAutoArrange');

        // Open Print Settings
        printBtn.addEventListener('click', () => {
            // Validate if there is something to print
            const isPreviewVisible = preview.style.display !== 'none' && preview.getAttribute('src') !== '#' && preview.src;
            const isCanvasVisible = cropCanvas.style.display !== 'none';

            if (!isPreviewVisible && !isCanvasVisible) {
                alert('Tidak ada gambar untuk dicetak!');
                return;
            }

            // Defaults
            printCopiesInput.value = 1;
            printAutoArrange.checked = currentDocType === 'ktp'; // Default on for KTP
            printSettingsModal.style.display = 'block';
        });

        // Close Print Settings
        function closePrintModal() {
            printSettingsModal.style.display = 'none';
        }
        closePrintBtn.addEventListener('click', closePrintModal);
        cancelPrintBtn.addEventListener('click', closePrintModal);

        // Confirm Print
        confirmPrintBtn.addEventListener('click', () => {
            const printArea = document.getElementById('printArea');
            printArea.innerHTML = ''; // Clear previous

            // Determine Source Image
            let imgSrc = '';
            let isCropCanvas = false;

            // Prioritize Preview (Result/Archive), then Crop Canvas (Editing)
            if (preview.style.display !== 'none' && preview.getAttribute('src') !== '#' && preview.src) {
                imgSrc = preview.src;
            } else if (cropCanvas.style.display !== 'none') {
                // Use Canvas Data
                imgSrc = cropCanvas.toDataURL('image/jpeg', 0.95);
                isCropCanvas = true;
            }

            if (!imgSrc) {
                alert('Gagal mengambil gambar source.');
                closePrintModal();
                return;
            }

            const copies = parseInt(printCopiesInput.value) || 1;

            // KTP Logic: Duplicate N times
            if (currentDocType === 'ktp') {
                for (let i = 0; i < copies; i++) {
                    const img = document.createElement('img');
                    img.src = imgSrc;
                    img.className = 'ktp-print-item';
                    printArea.appendChild(img);
                }

                // Apply Grid? CSS handles #printArea display: grid by default in @media print
                // We can force toggle if needed, but CSS is cleaner.
                // If User unchecks "Auto Arrange", we could change class to block?
                if (!printAutoArrange.checked) {
                    printArea.style.display = 'block'; // Override grid
                    // Add page breaks or margins? 
                    // For non-arranged, maybe just list them? 
                    // Let's stick to Grid as default default. If unchecked, maybe just normal flow?
                    // Actually, user wants "Save Paper" (Grid) vs "One per page"?
                    // Let's assume unchecked means "Standard Flow" which might just be grid anyway but maybe less aggressive?
                    // For now, let's keep it simple: Grid is always active for KTP if multiple copies.
                    // A simple way to respect "No Auto Arrange" is to force page break?
                    // User request: "Jangan ditaruh di tengah... hemat kertas" -> Default Grid is the solution.
                } else {
                    printArea.style.removeProperty('display'); // Use CSS default (grid)
                }

            } else {
                // KK / A4 Logic
                // Usually 1 copy per page, or just N copies
                for (let i = 0; i < copies; i++) {
                    const img = document.createElement('img');
                    img.src = imgSrc;
                    img.className = 'a4-print-size';
                    printArea.appendChild(img);
                }
            }

            closePrintModal();

            // Wait a bit for images to render in hidden DOM
            setTimeout(() => {
                window.print();
            }, 300);
        });

        // Download functionality
        const downloadBtn = document.getElementById('downloadBtn');
        downloadBtn.addEventListener('click', () => {
            // Check if preview is valid
            const isPreviewVisible = preview.style.display !== 'none' && preview.getAttribute('src') !== '#' && preview.src;

            if (!isPreviewVisible) {
                if (cropCanvas.style.display !== 'none') {
                    // Allow download canvas
                    const link = document.createElement('a');
                    link.download = 'ktp_scan_raw.jpg';
                    link.href = cropCanvas.toDataURL('image/jpeg', 0.95);
                    link.click();
                    return;
                }
                alert('Tidak ada gambar untuk diunduh');
                return;
            }

            const link = document.createElement('a');
            link.href = preview.src;

            // Construct filename from Extracted Data if available
            let filename = 'ktp_scan.jpg';
            const nikInput = document.getElementById('field-nik'); // ID format might be different, let's check render logic
            // renderEditableFields generates identifiers? No, extractedData global var is safest.
            if (typeof extractedData !== 'undefined' && extractedData.nik) {
                filename = `KTP_${extractedData.nik}.jpg`;
            } else {
                // Try getting from DOM inputs if extractedData not set
                const domNik = document.querySelector('input[data-key="nik"]');
                if (domNik && domNik.value) filename = `KTP_${domNik.value}.jpg`;
            }

            link.download = filename;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        });

        // Archive Modal Logic
        const archiveBtn = document.getElementById('archiveBtn');
        const archiveModal = document.getElementById('archiveModal');
        const closeModalBtn = document.getElementById('closeModalBtn');
        const archiveList = document.getElementById('archiveList');
        const archiveLoading = document.getElementById('archiveLoading');
        const archiveEmpty = document.getElementById('archiveEmpty');

        // Login Logic Vars
        const loginModal = document.getElementById('loginModal');
        const loginUser = document.getElementById('loginUser');
        const loginPass = document.getElementById('loginPass');
        const submitLoginBtn = document.getElementById('submitLoginBtn');
        const loginError = document.getElementById('loginError');
        const closeLoginBtn = document.getElementById('closeLoginBtn');

        // Check Auth Helper
        async function checkAuth() {
            try {
                const res = await fetch('/api/check-auth');
                if (res.ok) {
                    const data = await res.json();
                    return data.authenticated;
                }
                return false;
            } catch (e) { return false; }
        }

        // Archive Button Logic
        // const archiveBtn = document.getElementById('archiveBtn'); // Already declared
        const archiveKKBtn = document.getElementById('archiveKKBtn');

        async function openArchive(type) {
            currentArchiveType = type;
            const title = type === 'kk' ? 'Arsip Kartu Keluarga' : 'Arsip KTP';
            document.querySelector('#archiveModal h2').textContent = '📂 ' + title;

            if (await checkAuth()) {
                archiveModal.style.display = 'block';
                loadArchive();
            } else {
                loginModal.style.display = 'block';
                // Reset login form
                loginPass.value = '';
                loginError.style.display = 'none';
                loginPass.focus();
            }
        }

        archiveBtn.addEventListener('click', () => openArchive('ktp'));
        if (archiveKKBtn) {
            archiveKKBtn.addEventListener('click', () => openArchive('kk'));
        }

        // Submit Login Logic
        submitLoginBtn.addEventListener('click', async () => {
            const user = loginUser.value;
            const pass = loginPass.value;

            if (!user || !pass) {
                loginError.textContent = 'Username dan Password harus diisi';
                loginError.style.display = 'block';
                return;
            }

            loginError.style.display = 'none';
            submitLoginBtn.disabled = true;
            submitLoginBtn.innerHTML = 'Memeriksa...';

            try {
                const res = await fetch('/api/login', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ username: user, password: pass })
                });
                const data = await res.json();

                if (data.success) {
                    loginModal.style.display = 'none';
                    archiveModal.style.display = 'block';
                    loadArchive();
                } else {
                    loginError.textContent = data.error || 'Login gagal';
                    loginError.style.display = 'block';
                }
            } catch (e) {
                loginError.textContent = 'Gagal terhubung ke server';
                loginError.style.display = 'block';
            } finally {
                submitLoginBtn.disabled = false;
                submitLoginBtn.innerHTML = 'Masuk';
            }
        });

        // Handle Enter Key
        loginPass.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') submitLoginBtn.click();
        });

        // Close Login Modal
        closeLoginBtn.addEventListener('click', () => { loginModal.style.display = 'none'; });
        // Close Archive Modal (Restored)
        closeModalBtn.addEventListener('click', () => { archiveModal.style.display = 'none'; });

        // Window click handler for both modals
        window.addEventListener('click', (e) => {
            if (e.target === archiveModal) archiveModal.style.display = 'none';
            if (e.target === loginModal) loginModal.style.display = 'none';
            if (e.target === printSettingsModal) printSettingsModal.style.display = 'none';
        });

        async function loadArchive() {
            archiveList.innerHTML = '';
            archiveLoading.style.display = 'block';
            archiveEmpty.style.display = 'none';

            try {
                const endpoint = `/api/${currentArchiveType}-archive?per_page=50`;
                const response = await fetch(endpoint);
                const result = await response.json();

                archiveLoading.style.display = 'none';

                if (result.success && result.data.length > 0) {
                    renderArchiveList(result.data);
                } else {
                    archiveEmpty.style.display = 'block';
                }
            } catch (error) {
                console.error('Archive load error:', error);
                archiveLoading.innerHTML = '❌ Gagal memuat data';
            }
        }

        function renderArchiveList(records) {
            const imgPrefix = currentArchiveType === 'kk' ? '/kk-images/' : '/ktp-images/';

            records.forEach(record => {
                const card = document.createElement('div');
                card.className = 'archive-card';

                const date = new Date(record.created_at).toLocaleDateString('id-ID', {
                    year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit'
                });

                const title = currentArchiveType === 'kk' ? (record.kepala_keluarga || 'Tanpa Nama') : (record.nama || 'Tanpa Nama');
                const idVal = currentArchiveType === 'kk' ? (record.no_kk || '-') : (record.nik || '-');

                card.innerHTML = `
                    <div class="archive-card-img">
                        <img src="${imgPrefix}${record.image_path}" alt="${title}" loading="lazy">
                    </div>
                    <div class="archive-card-content">
                        <h3>${title}</h3>
                        <div class="archive-card-meta">
                            <span class="nik">${idVal}</span>
                            <span class="date">${date}</span>
                        </div>
                        <div class="archive-card-actions" style="display:flex; gap:0.5rem;">
                            <button class="view-btn" onclick='viewArchiveDetail(${JSON.stringify(record).replace(/'/g, "&#39;")})' style="flex:1;">👁️ Lihat</button>
                            <a href="${imgPrefix}${record.image_path}" download="${currentArchiveType.toUpperCase()}_${idVal}.jpg" class="view-btn" style="flex:1; text-align:center; text-decoration:none; display:flex; align-items:center; justify-content:center;">⬇️</a>
                        </div>
                    </div>
                `;
                archiveList.appendChild(card);
            });
        }

        // Global function to view detail from archive
        window.viewArchiveDetail = (record) => {
            extractedData = record;
            currentDocType = currentArchiveType; // Sync type so Save works correctly

            // 1. Display results
            displayResults({ data: record, raw_text: record.raw_text || '' });

            // 2. Load image into preview
            if (record.image_path) {
                const imgPrefix = currentArchiveType === 'kk' ? '/kk-images/' : '/ktp-images/';
                const imgUrl = `${imgPrefix}${record.image_path}`;
                preview.src = imgUrl;

                // Set originalImageData to allow re-cropping or re-saving if needed
                fetch(imgUrl)
                    .then(res => res.blob())
                    .then(blob => {
                        const reader = new FileReader();
                        reader.onloadend = () => {
                            originalImageData = reader.result;
                            selectedFile = new File([blob], record.image_path, { type: blob.type });

                            // Initialize Image Object for rotation editor
                            const img = new Image();
                            img.onload = () => {
                                originalImageObject = img;
                                // We don't necessarily need to renderEditor() immediately if we are in "View" mode
                                // But having it ready is good for "Reset"
                            };
                            img.src = reader.result;
                        };
                        reader.readAsDataURL(blob);
                    });

                // Show preview area (static image result), hide dropzone/canvas
                preview.style.display = 'block';
                cropCanvas.style.display = 'none';
                dropzone.querySelector('.dropzone-content').style.display = 'none';

                // Setup crop ui visibility
                cropContainer.style.display = 'block';
                cropArea.style.display = 'none';
                cropActions.style.display = 'flex';

                // Reset rotation slider for viewing (since we are viewing already cropped/straightened result)
                currentRotation = 0;
                updateRotationUI();
            }

            archiveModal.style.display = 'none';
        };

        // Reload Button
        document.getElementById('reloadBtn').addEventListener('click', () => {
            window.location.reload();
        });
    </script>
    <!-- Print Area -->
    <div id="printArea"></div>

    <script>
        // ... (this comment is just marker, main script is above)
    </script>
</body>

</html>