<?php
include('../includes/session.php');
include('../includes/config.php');
include('../template/tngweb/header.php');

/* ===== DATE FILTER (DEFAULT TODAY) ===== */
$from = $_GET['from'] ?? date('Y-m-d');
$to   = $_GET['to']   ?? date('Y-m-d');

$fromSql = mysqli_real_escape_string($tng_conn,$from.' 00:00:00');
$toSql   = mysqli_real_escape_string($tng_conn,$to.' 23:59:59');
?>

<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">

<style>
/* PDF Viewer Modal for PAN Manual */
.pan-viewer-modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.9);
    z-index: 9999;
    animation: fadeIn 0.3s;
}
.pan-viewer-content {
    position: relative;
    width: 90%;
    height: 90%;
    margin: 2% auto;
    background: #fff;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 10px 40px rgba(0,0,0,0.3);
}
.pan-viewer-content iframe {
    width: 100%;
    height: calc(100% - 50px);
    border: none;
}
.pan-viewer-header {
    padding: 12px 20px;
    background: #1e293b;
    color: white;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.pan-viewer-header h5 {
    margin: 0;
}
.close-pan-viewer {
    background: none;
    border: none;
    color: white;
    font-size: 28px;
    cursor: pointer;
    transition: 0.3s;
}
.close-pan-viewer:hover {
    color: #ef4444;
}
@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}
.swal-wide {
    width: 90% !important;
    max-width: 1200px !important;
}
.image-preview {
    max-width: 150px;
    max-height: 150px;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    cursor: pointer;
    transition: transform 0.2s;
}
.image-preview:hover {
    transform: scale(1.05);
}
.json-image-cell {
    text-align: center;
    vertical-align: middle;
}
</style>

<div class="page-wrapper">
<div class="page-content">

<div class="card luxury-card">
<div class="card-body">

<div class="d-flex justify-content-between align-items-center mb-3">
  <a href="javascript:history.back()" class="btn btn-outline-primary rounded-pill px-4">
    <i class="bi bi-arrow-left-circle me-2"></i> Go Back
  </a>
  <h5 class="fw-bold text-primary mb-0">📂 All PDF / Service History</h5>
</div>

<hr>

<!-- DATE FILTER -->
<form method="get" class="row g-3 align-items-end mb-3">
  <div class="col-md-3">
    <label class="fw-semibold">From Date</label>
    <input type="date" name="from" value="<?= htmlspecialchars($from) ?>" class="form-control rounded-pill">
  </div>
  <div class="col-md-3">
    <label class="fw-semibold">To Date</label>
    <input type="date" name="to" value="<?= htmlspecialchars($to) ?>" class="form-control rounded-pill">
  </div>
  <div class="col-md-4">
    <button class="btn btn-primary rounded-pill px-4 me-2">🔍 Filter</button>
    <a href="all_history.php" class="btn btn-outline-secondary rounded-pill px-4">♻ Today</a>
  </div>
</form>

<div class="table-responsive">
<table id="walletTable" class="table table-hover luxury-table align-middle text-center">
<thead>
<tr>
  <th>Sr No</th>
  <th>Service</th>
  <th>Name</th>
  <th>Number</th>
  <th>Date</th>
  <th>Action</th>
</tr>
</thead>
<tbody>

<?php
if ($udata['type'] === 'admin') {
    $res = mysqli_query($tng_conn, "SELECT * FROM all_pdf_records WHERE date BETWEEN '$fromSql' AND '$toSql' ORDER BY date DESC");
} else {
    $phone = mysqli_real_escape_string($tng_conn, $udata['phone']);
    $res = mysqli_query($tng_conn, "SELECT * FROM all_pdf_records WHERE username='$phone' AND date BETWEEN '$fromSql' AND '$toSql' ORDER BY date DESC");
}

while($row = mysqli_fetch_assoc($res)){

$raw = trim($row['pdf']);
$serviceName = strtoupper(str_replace('_',' ',$row['service_name']));

/* ===== FILE NAME ===== */
$nameRaw = $row['service_name'].'_'.$row['name'].'_'.$row['number'];
$nameRaw = preg_replace('/\s+/', '_', $nameRaw);
$nameRaw = preg_replace('/[^a-zA-Z0-9_]/', '_', $nameRaw);
$nameRaw = preg_replace('/_+/', '_', $nameRaw);
$fileName = strtoupper(trim($nameRaw,'_'));

/* ===== TYPE DETECT ===== */
$isPdf   = strpos($raw, 'data:application/pdf;base64,') === 0;
$isImage = preg_match('#^data:image/(png|jpeg|jpg);base64,#', $raw);
$isBase64Json = !$isPdf && !$isImage && !empty($raw);

// For PAN MANUAL - check if service is PAN_MANUAL
$isPanManual = ($row['service_name'] === 'PAN_MANUAL');

// For JSON data (base64 encoded)
$decodedData = '';
$panId = '';
if($isBase64Json && !$isPanManual){
    $decodedData = base64_decode($raw);
    // Try to extract ID if present
    $jsonData = json_decode($decodedData, true);
    if(isset($jsonData['id'])){
        $panId = $jsonData['id'];
    }
}
?>

<tr>
  <td><?= $row['id'] ?></td>
  <td><span class="badge bg-info text-dark px-3 py-2"><?= $serviceName ?></span></td>
  <td><?= htmlspecialchars($row['name']) ?></td>
  <td><?= htmlspecialchars($row['number']) ?></td>
  <td data-order="<?= strtotime($row['date']) ?>"><?= date("d M Y h:i A",strtotime($row['date'])) ?></td>
  <td>
    <?php if($isPdf){ ?>
        <div class="btn-group" role="group">
            <button class="btn btn-primary btn-sm rounded-pill px-3 me-1 viewPdfBtn"
                    data-pdf="<?= htmlspecialchars($raw, ENT_QUOTES) ?>"
                    data-name="<?= htmlspecialchars($row['name']) ?>">
                <i class="fas fa-eye"></i> View
            </button>
            <button class="btn btn-success btn-sm rounded-pill px-3 downloadPdfBtn"
                    data-pdf="<?= htmlspecialchars($raw, ENT_QUOTES) ?>"
                    data-file="<?= htmlspecialchars($fileName, ENT_QUOTES) ?>">
                <i class="fas fa-download"></i> Download
            </button>
        </div>
    <?php } elseif($isImage){ ?>
        <div class="btn-group" role="group">
            <button class="btn btn-primary btn-sm rounded-pill px-3 me-1 viewImageBtn"
                    data-image="<?= htmlspecialchars($raw, ENT_QUOTES) ?>"
                    data-name="<?= htmlspecialchars($row['name']) ?>">
                <i class="fas fa-eye"></i> View
            </button>
            <button class="btn btn-success btn-sm rounded-pill px-3 downloadImageBtn"
                    data-image="<?= htmlspecialchars($raw, ENT_QUOTES) ?>"
                    data-file="<?= htmlspecialchars($fileName, ENT_QUOTES) ?>">
                <i class="fas fa-download"></i> Download
            </button>
        </div>
    <?php } elseif($isPanManual){ 
        // For PAN MANUAL - extract ID from JSON
        $jsonData = json_decode(base64_decode($raw), true);
        $panId = $jsonData['id'] ?? $row['id'] ?? '';
        $panUrl = baseurl() . "/admin/pan/pan.php?searchid=" . $panId;
    ?>
        <div class="btn-group" role="group">
            <button class="btn btn-primary btn-sm rounded-pill px-3 me-1 viewPanBtn"
                    data-url="<?= htmlspecialchars($panUrl, ENT_QUOTES) ?>"
                    data-name="<?= htmlspecialchars($row['name']) ?>">
                <i class="fas fa-eye"></i> View PAN
            </button>
            <button class="btn btn-success btn-sm rounded-pill px-3 downloadPanBtn"
                    data-url="<?= htmlspecialchars($panUrl, ENT_QUOTES) ?>"
                    data-file="<?= htmlspecialchars($fileName, ENT_QUOTES) ?>">
                <i class="fas fa-download"></i> Download PDF
            </button>
        </div>
    <?php } elseif($isBase64Json){ ?>
        <div class="btn-group" role="group">
            <button class="btn btn-primary btn-sm rounded-pill px-3 me-1 viewJsonBtn"
                    data-json='<?= htmlspecialchars($decodedData, ENT_QUOTES) ?>'
                    data-name="<?= htmlspecialchars($row['name']) ?>">
                <i class="fas fa-eye"></i> View
            </button>
            <button class="btn btn-success btn-sm rounded-pill px-3 downloadJsonAsPdfBtn"
                    data-json='<?= htmlspecialchars($decodedData, ENT_QUOTES) ?>'
                    data-file="<?= htmlspecialchars($fileName, ENT_QUOTES) ?>">
                <i class="fas fa-download"></i> Download PDF
            </button>
        </div>
    <?php } else { ?>
        <span class="text-muted">N/A</span>
    <?php } ?>
  </td>
</tr>

<?php } ?>
</tbody>
</table>
</div>

</div>
</div>
</div>
</div>

<!-- PAN Viewer Modal -->
<div id="panViewerModal" class="pan-viewer-modal">
    <div class="pan-viewer-content">
        <div class="pan-viewer-header">
            <h5><i class="fas fa-id-card"></i> PAN Card Preview</h5>
            <button class="close-pan-viewer" onclick="closePanViewer()">&times;</button>
        </div>
        <iframe id="panIframe" src=""></iframe>
    </div>
</div>

<?php include('../template/tngweb/footer.php'); ?>

<!-- Scripts -->
<script src="../template/tngweb/assets/plugins/simplebar/js/simplebar.min.js"></script>
<script src="../template/tngweb/assets/plugins/metismenu/js/metisMenu.min.js"></script>
<script src="../template/tngweb/assets/plugins/perfect-scrollbar/js/perfect-scrollbar.js"></script>
<script src="../template/tngweb/assets/js/app.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>

<script>
$(function(){
    const table = $('#walletTable').DataTable({
        pageLength: 10,
        lengthChange: false,
        order: [[4, 'desc']],
        columnDefs: [{orderable: false, targets: [5]}]
    });
});

// ================= PDF VIEW & DOWNLOAD (Swal Fire) =================
function viewPdfInSwal(pdfDataUrl, name) {
    try {
        const base64 = pdfDataUrl.replace(/^data:application\/pdf;base64,/, '');
        const byteCharacters = atob(base64);
        const byteArrays = [];
        const sliceSize = 1024;
        
        for(let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            const slice = byteCharacters.slice(offset, offset + sliceSize);
            const byteNumbers = new Array(slice.length);
            for(let i = 0; i < slice.length; i++) {
                byteNumbers[i] = slice.charCodeAt(i);
            }
            byteArrays.push(new Uint8Array(byteNumbers));
        }
        
        const blob = new Blob(byteArrays, {type: 'application/pdf'});
        const blobUrl = URL.createObjectURL(blob);
        
        Swal.fire({
            title: name || 'PDF Viewer',
            html: `<iframe src="${blobUrl}" style="width:100%; height:70vh; border:none;"></iframe>`,
            width: '90%',
            showCloseButton: true,
            showConfirmButton: false,
            customClass: { popup: 'swal-wide' },
            didDestroy: () => URL.revokeObjectURL(blobUrl)
        });
    } catch(e) {
        Swal.fire('Error', 'Cannot open PDF', 'error');
    }
}

function downloadPdf(pdfDataUrl, filename) {
    try {
        const base64 = pdfDataUrl.replace(/^data:application\/pdf;base64,/, '');
        const byteCharacters = atob(base64);
        const byteArrays = [];
        const sliceSize = 1024;
        
        for(let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            const slice = byteCharacters.slice(offset, offset + sliceSize);
            const byteNumbers = new Array(slice.length);
            for(let i = 0; i < slice.length; i++) {
                byteNumbers[i] = slice.charCodeAt(i);
            }
            byteArrays.push(new Uint8Array(byteNumbers));
        }
        
        const blob = new Blob(byteArrays, {type: 'application/pdf'});
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename + '.pdf';
        document.body.appendChild(a);
        a.click();
        setTimeout(() => {
            URL.revokeObjectURL(url);
            a.remove();
        }, 3000);
    } catch(e) {
        Swal.fire('Error', 'PDF download failed', 'error');
    }
}

// ================= IMAGE VIEW & DOWNLOAD (Swal Fire) =================
function viewImageInSwal(imageDataUrl, name) {
    Swal.fire({
        title: name || 'Image Preview',
        imageUrl: imageDataUrl,
        imageWidth: '90%',
        imageHeight: 'auto',
        imageAlt: 'Image Preview',
        showCloseButton: true,
        showConfirmButton: false,
        customClass: { popup: 'swal-wide' }
    });
}

function downloadImage(imageDataUrl, filename) {
    try {
        const arr = imageDataUrl.split(',');
        const mime = arr[0].match(/:(.*?);/)[1];
        const bstr = atob(arr[1]);
        const u8 = new Uint8Array(bstr.length);
        for(let i = 0; i < bstr.length; i++) u8[i] = bstr.charCodeAt(i);
        
        const blob = new Blob([u8], {type: mime});
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename + '.png';
        document.body.appendChild(a);
        a.click();
        setTimeout(() => {
            URL.revokeObjectURL(url);
            a.remove();
        }, 3000);
    } catch(e) {
        Swal.fire('Error', 'Image download failed', 'error');
    }
}

// ================= JSON VIEW & DOWNLOAD AS PDF =================

// Check if value is an image data URL
function isImageData(value) {
    return typeof value === 'string' && (value.startsWith('data:image/jpeg;base64,') || 
           value.startsWith('data:image/png;base64,') || 
           value.startsWith('data:image/jpg;base64,') ||
           value.startsWith('data:image/gif;base64,'));
}

// Format key name - automatically handles any field name
function formatKey(key) {
    return key.replace(/_/g, ' ')
              .replace(/([A-Z])/g, ' $1')
              .replace(/^./, c => c.toUpperCase())
              .trim();
}

// Render JSON with images - poora response dikhega, image wali fields mein image dikhegi
function renderJsonWithImages(d, c) {
    if(d === null || typeof d !== 'object') {
        c.appendChild(createValueElement(d));
        return;
    }
    if(Array.isArray(d)) {
        d.forEach((i, x) => {
            const box = document.createElement('div');
            box.className = 'json-card';
            box.innerHTML = `<div class="json-card-title">Item ${x+1}</div>`;
            renderJsonWithImages(i, box);
            c.appendChild(box);
        });
        return;
    }
    const t = document.createElement('table');
    t.className = 'table table-bordered json-table';
    for(const k in d) {
        const tr = document.createElement('tr');
        const th = document.createElement('th');
        const td = document.createElement('td');
        th.innerText = formatKey(k);
        if(isImageData(d[k])) {
            td.className = 'json-image-cell';
        }
        renderJsonWithImages(d[k], td);
        tr.appendChild(th);
        tr.appendChild(td);
        t.appendChild(tr);
    }
    c.appendChild(t);
}

// Create value element - image ya text
function createValueElement(v) {
    const s = document.createElement('span');
    s.className = 'json-value';
    
    if(v === null || v === '') {
        s.innerText = '-';
    } else if(typeof v === 'object') {
        s.innerText = JSON.stringify(v);
    } else if(isImageData(v)) {
        const img = document.createElement('img');
        img.src = v;
        img.className = 'image-preview';
        img.title = 'Click to view full size';
        img.onclick = function(e) {
            e.stopPropagation();
            Swal.fire({
                imageUrl: v,
                imageAlt: 'Full Size Image',
                imageWidth: '80%',
                imageHeight: 'auto',
                showCloseButton: true,
                showConfirmButton: false
            });
        };
        s.appendChild(img);
    } else {
        let displayValue = v;
        if(typeof v === 'string' && v.length > 200) {
            displayValue = v.substring(0, 200) + '... (truncated)';
        }
        s.innerText = displayValue;
    }
    return s;
}

// Collect text for copy (image ko [IMAGE] show karega)
function collectTextForCopy(data, container) {
    if (data === null || typeof data !== 'object') {
        if (isImageData(data)) {
            container.appendChild(document.createTextNode('[IMAGE]'));
        } else {
            container.appendChild(document.createTextNode(String(data)));
        }
        return;
    }
    if (Array.isArray(data)) {
        data.forEach((item, idx) => {
            collectTextForCopy(item, container);
            if (idx < data.length - 1) container.appendChild(document.createTextNode(', '));
        });
        return;
    }
    for (const key in data) {
        container.appendChild(document.createTextNode(`${formatKey(key)}: `));
        collectTextForCopy(data[key], container);
        container.appendChild(document.createTextNode('\n'));
    }
}

// Main JSON View Function
function viewJsonInSwal(jsonData, name) {
    let data;
    try {
        data = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData;
    } catch(e) {
        data = jsonData;
    }
    
    const container = document.createElement('div');
    container.className = 'json-root';
    renderJsonWithImages(data, container);
    
    Swal.fire({
        title: name || '📄 Service Details',
        html: container,
        width: '90%',
        showCancelButton: true,
        confirmButtonText: '📋 Copy Details',
        cancelButtonText: '❌ Close',
        customClass: { popup: 'swal-wide' },
        didOpen: () => {
            const copyDiv = document.createElement('div');
            collectTextForCopy(data, copyDiv);
            window.__COPY = copyDiv.innerText.trim();
        },
        preConfirm: () => {
            navigator.clipboard.writeText(window.__COPY);
            Swal.fire('Copied', 'Details copied to clipboard', 'success');
            return false;
        }
    });
}

// Generate PDF HTML - poora response + images
function generatePdfHtml(data) {
    if (data === null || typeof data !== 'object') {
        if (isImageData(data)) {
            return `<img src="${data}" class="pdf-image" />`;
        }
        return String(data || '-');
    }
    
    if (Array.isArray(data)) {
        let html = '';
        data.forEach((item, index) => {
            html += `<div class="json-card"><div class="json-card-title">Item ${index + 1}</div>`;
            html += `<table class="pdf-table">`;
            for (const [key, value] of Object.entries(item)) {
                html += `<tr><th>${formatKey(key)}</th><td>${generatePdfHtml(value)}</td></tr>`;
            }
            html += `</table></div>`;
        });
        return html;
    }
    
    let html = `<table class="pdf-table">`;
    for (const [key, value] of Object.entries(data)) {
        html += `<tr><th>${formatKey(key)}</th><td>${generatePdfHtml(value)}</td></tr>`;
    }
    html += `</table>`;
    return html;
}

// Download JSON as PDF
function downloadJsonAsPdf(jsonData, filename) {
    let data;
    try {
        data = typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData;
    } catch(e) {
        data = jsonData;
    }
    
    let htmlContent = `
    <!DOCTYPE html>
    <html>
    <head>
        <title>${filename}</title>
        <style>
            body { font-family: Arial, sans-serif; padding: 20px; }
            h1 { color: #1e293b; text-align: center; font-size: 18px; }
            .pdf-table { width: 100%; border-collapse: collapse; margin-top: 10px; }
            .pdf-table th, .pdf-table td { border: 1px solid #ddd; padding: 8px; text-align: left; vertical-align: top; }
            .pdf-table th { background-color: #f2f2f2; width: 30%; }
            .json-card { border: 1px solid #ddd; border-radius: 8px; padding: 15px; margin-bottom: 15px; }
            .json-card-title { font-weight: bold; color: #4338ca; margin-bottom: 10px; }
            .pdf-image { max-width: 200px; max-height: 200px; }
        </style>
    </head>
    <body>
        <h1>Service Details: ${filename}</h1>
    `;
    
    htmlContent += generatePdfHtml(data);
    htmlContent += `</body></html>`;
    
    const opt = {
        margin: [0.5, 0.5, 0.5, 0.5],
        filename: filename + '.pdf',
        image: { type: 'jpeg', quality: 0.98 },
        html2canvas: { scale: 2 },
        jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait' }
    };
    
    html2pdf().set(opt).from(htmlContent).save();
}

// ================= PAN MANUAL VIEW (URL based) =================
function openPanViewer(url, name) {
    const modal = document.getElementById('panViewerModal');
    const iframe = document.getElementById('panIframe');
    iframe.src = url;
    modal.style.display = 'block';
    
    const header = modal.querySelector('.pan-viewer-header h5');
    if(header) header.innerHTML = `<i class="fas fa-id-card"></i> PAN Card: ${name || 'Preview'}`;
}

function closePanViewer() {
    const modal = document.getElementById('panViewerModal');
    const iframe = document.getElementById('panIframe');
    modal.style.display = 'none';
    iframe.src = '';
}

function downloadPanAsPdf(url, filename) {
    const win = window.open(url, '_blank');
    if(win) {
        Swal.fire('Info', 'PAN Card opened in new tab. Use browser print (Ctrl+P) to save as PDF', 'info');
    } else {
        Swal.fire('Error', 'Popup blocked! Please allow popups for this site', 'error');
    }
}

document.addEventListener('keydown', function(e) {
    if(e.key === 'Escape') {
        closePanViewer();
    }
});

// ================= EVENT LISTENERS =================
document.addEventListener('click', function(e) {
    const viewPdfBtn = e.target.closest('.viewPdfBtn');
    if(viewPdfBtn) {
        const pdfData = viewPdfBtn.getAttribute('data-pdf');
        const name = viewPdfBtn.getAttribute('data-name');
        viewPdfInSwal(pdfData, name);
        return;
    }
    
    const downloadPdfBtn = e.target.closest('.downloadPdfBtn');
    if(downloadPdfBtn) {
        const pdfData = downloadPdfBtn.getAttribute('data-pdf');
        const filename = downloadPdfBtn.getAttribute('data-file');
        downloadPdf(pdfData, filename);
        return;
    }
    
    const viewImageBtn = e.target.closest('.viewImageBtn');
    if(viewImageBtn) {
        const imageData = viewImageBtn.getAttribute('data-image');
        const name = viewImageBtn.getAttribute('data-name');
        viewImageInSwal(imageData, name);
        return;
    }
    
    const downloadImageBtn = e.target.closest('.downloadImageBtn');
    if(downloadImageBtn) {
        const imageData = downloadImageBtn.getAttribute('data-image');
        const filename = downloadImageBtn.getAttribute('data-file');
        downloadImage(imageData, filename);
        return;
    }
    
    const viewJsonBtn = e.target.closest('.viewJsonBtn');
    if(viewJsonBtn) {
        const jsonData = viewJsonBtn.getAttribute('data-json');
        const name = viewJsonBtn.getAttribute('data-name');
        viewJsonInSwal(jsonData, name);
        return;
    }
    
    const downloadJsonAsPdfBtn = e.target.closest('.downloadJsonAsPdfBtn');
    if(downloadJsonAsPdfBtn) {
        const jsonData = downloadJsonAsPdfBtn.getAttribute('data-json');
        const filename = downloadJsonAsPdfBtn.getAttribute('data-file');
        downloadJsonAsPdf(jsonData, filename);
        return;
    }
    
    const viewPanBtn = e.target.closest('.viewPanBtn');
    if(viewPanBtn) {
        const url = viewPanBtn.getAttribute('data-url');
        const name = viewPanBtn.getAttribute('data-name');
        openPanViewer(url, name);
        return;
    }
    
    const downloadPanBtn = e.target.closest('.downloadPanBtn');
    if(downloadPanBtn) {
        const url = downloadPanBtn.getAttribute('data-url');
        const filename = downloadPanBtn.getAttribute('data-file');
        downloadPanAsPdf(url, filename);
        return;
    }
});
</script>

<style>
body{background:#f4f6fb}
.luxury-card{
  border-radius:20px;
  background:linear-gradient(145deg,#fff,#eef2ff);
  box-shadow:0 20px 40px rgba(0,0,0,.08);
}
.luxury-table thead th{ 
  background:linear-gradient(135deg,#1e1e2f,#2f3350);
  color:#fff;
}
.luxury-table tbody tr:hover{background:#eef2ff}
.swal-wide{width:90%!important;max-width:1200px!important}
.json-root{max-height:70vh;overflow:auto}
.json-table th{width:30%;background:#eef2ff;font-weight:600}
.json-card{
  background:#fff;border-radius:16px;
  padding:14px;margin-bottom:14px;
  box-shadow:0 10px 25px rgba(0,0,0,.06)
}
.json-card-title{font-weight:700;color:#4338ca;margin-bottom:8px}
.json-value{
  background:#f8fafc;
  padding:6px 10px;
  border-radius:8px;
  display:inline-block;
  word-break:break-all;
}
.btn-group .btn {
    font-size: 12px;
    padding: 6px 12px;
}
.image-preview {
    max-width: 150px;
    max-height: 150px;
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    cursor: pointer;
    transition: transform 0.2s;
}
.image-preview:hover {
    transform: scale(1.05);
}
.json-image-cell {
    text-align: center;
    vertical-align: middle;
}
</style>
</html>