@extends('admin.layouts.app')
@section('title', 'Anime İçe Aktar')
@section('page-title', 'Anime İçe Aktar')

@push('styles')
<style>
.job-card {
    background:var(--bg2); border:1px solid var(--border);
    border-radius:var(--radius); padding:16px 20px; margin-bottom:12px;
    transition:border-color .15s;
}
.job-card:hover { border-color:var(--border2); }
.test-output {
    display:none;
    background:var(--bg);
    border:1px solid var(--border);
    border-radius:var(--radius-sm);
    padding:14px;
    font-size:12px;
    font-family:'JetBrains Mono',monospace;
    white-space:pre-wrap;
    max-height:200px;
    overflow:auto;
    margin-top:12px;
}
</style>
@endpush

@section('content')

<div class="page-header">
    <div>
        <h5 style="font-size:18px;font-weight:700;color:var(--text);margin:0">Anime İçe Aktar</h5>
        <div style="font-size:13px;color:var(--text2);margin-top:2px">CDN bağlantısından otomatik anime indirme</div>
    </div>
</div>

<div class="row g-4">

    {{-- ── Sol: Form ── --}}
    <div class="col-lg-5">

        <div class="card mb-3">
            <div class="card-header">
                <i class="bi bi-cloud-download" style="color:var(--accent-lt)"></i>
                <h6>Yeni Import Job Oluştur</h6>
            </div>
            <div class="card-body">
                <form method="POST" action="{{ route('admin.import.store') }}">
                    @csrf

                    <div class="mb-3">
                        <label class="form-label">Anime URL <span style="color:var(--danger)">*</span></label>
                        <input type="url" name="source_url" class="form-control"
                               placeholder="https://anizium.co/watch/..." value="{{ old('source_url') }}" required>
                        <div class="form-text">Anizium watch veya anime sayfası URL'si</div>
                    </div>

                    <div class="mb-3">
                        <label class="form-label">Anime Adı <span style="color:var(--text2);font-size:11px">(opsiyonel)</span></label>
                        <input type="text" name="anime_title" class="form-control"
                               placeholder="Demon Slayer" value="{{ old('anime_title') }}">
                    </div>

                    <div class="mb-3">
                        <label class="form-label">CDN ID <span style="color:var(--text2);font-size:11px">(opsiyonel — otomatik bulunur)</span></label>
                        <input type="text" name="cdn_id" class="form-control"
                               style="font-family:monospace" placeholder="85937" value="{{ old('cdn_id') }}">
                        <div class="form-text">
                            URL'den al: <code>f.aniziumserver.sbs/<strong>85937</strong>/1/1/...</code>
                        </div>
                    </div>

                    <div class="mb-4">
                        <label class="form-label">
                            Sezon / Bölüm Aralıkları
                            <span style="color:var(--text2);font-size:11px">(opsiyonel — otomatik taranır)</span>
                        </label>
                        <div id="rangeRows">
                            @php $oldRanges = old('season_ranges',[['season'=>1,'from'=>1,'to'=>'']]) @endphp
                            @foreach($oldRanges as $i => $range)
                            <div class="range-row d-flex gap-2 mb-2 align-items-center">
                                <div style="flex:0 0 70px">
                                    <input type="number" name="season_ranges[{{ $i }}][season]"
                                           class="form-control form-control-sm text-center"
                                           placeholder="S" min="1" value="{{ $range['season']??1 }}" required>
                                </div>
                                <input type="number" name="season_ranges[{{ $i }}][from]"
                                       class="form-control form-control-sm text-center"
                                       placeholder="Baş" min="1" value="{{ $range['from']??'' }}" style="flex:1">
                                <span style="color:var(--text3);font-size:12px">—</span>
                                <input type="number" name="season_ranges[{{ $i }}][to]"
                                       class="form-control form-control-sm text-center"
                                       placeholder="Bit" min="1" value="{{ $range['to']??'' }}" style="flex:1">
                                <button type="button" class="btn btn-sm btn-outline-danger" onclick="removeRange(this)">
                                    <i class="bi bi-trash3"></i>
                                </button>
                            </div>
                            @endforeach
                        </div>
                        <button type="button" class="btn btn-sm btn-secondary mt-1" onclick="addRange()">
                            <i class="bi bi-plus-circle"></i> Sezon Ekle
                        </button>
                    </div>

                    <button type="submit" class="btn btn-primary w-100">
                        <i class="bi bi-download"></i> Import Job Oluştur
                    </button>
                </form>
            </div>
        </div>

        {{-- Test --}}
        <div class="card mb-3">
            <div class="card-header">
                <i class="bi bi-plug" style="color:var(--info)"></i>
                <h6>Bağlantı Testi</h6>
            </div>
            <div class="card-body">
                <div class="d-flex gap-2 mb-2">
                    <button type="button" class="btn btn-sm btn-secondary" onclick="testApi()">
                        <i class="bi bi-plug"></i> API Test
                    </button>
                    <button type="button" class="btn btn-sm btn-secondary" onclick="testCdn()">
                        <i class="bi bi-play-circle"></i> CDN Test
                    </button>
                </div>
                <div class="test-output" id="testResult"></div>
            </div>
        </div>

        {{-- ── Araçlar: Çift Kaynak + Altyazı Fix ── --}}
        <div class="card mb-3">
            <div class="card-header">
                <i class="bi bi-tools" style="color:var(--warning)"></i>
                <h6>Çift Kaynak Araçları</h6>
            </div>
            <div class="card-body" style="font-size:13px">

                {{-- İstatistikler --}}
                <div id="srcStats" style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:14px">
                    <div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:8px 10px;text-align:center">
                        <div style="font-size:11px;color:var(--text2)">İki kaynağı olan bölüm</div>
                        <div style="font-size:18px;font-weight:700;color:var(--success)" id="st-both">—</div>
                    </div>
                    <div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:8px 10px;text-align:center">
                        <div style="font-size:11px;color:var(--text2)">Altyazı hatası</div>
                        <div style="font-size:18px;font-weight:700;color:var(--danger)" id="st-sub">{{ $stats['subtitle_mismatch'] }}</div>
                    </div>
                    <div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:8px 10px;text-align:center">
                        <div style="font-size:11px;color:var(--text2)">Sadece Anizium</div>
                        <div style="font-size:18px;font-weight:700;color:var(--info)" id="st-aniz">—</div>
                    </div>
                    <div style="background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:8px 10px;text-align:center">
                        <div style="font-size:11px;color:var(--text2)">Sadece AnimeCix</div>
                        <div style="font-size:18px;font-weight:700;color:var(--accent)" id="st-acix">—</div>
                    </div>
                </div>
                <button class="btn btn-sm btn-secondary mb-3 w-100" onclick="loadStats()">
                    <i class="bi bi-arrow-clockwise"></i> İstatistikleri Yenile
                </button>

                <hr style="border-color:var(--border);margin:10px 0">

                {{-- Altyazı Fix --}}
                <div class="mb-3">
                    <div style="font-weight:600;color:var(--text);margin-bottom:6px">
                        <i class="bi bi-closed-caption" style="color:var(--danger)"></i>
                        Altyazı Uyuşmazlık Düzelt
                    </div>
                    <div style="color:var(--text2);font-size:12px;margin-bottom:8px">
                        Anizium'dan yanlış bölümün altyazısının kaydedildiği satırları siler.
                        Bot sonraki çalışmada doğru altyazıları yeniden indirir.
                    </div>
                    <div class="d-flex gap-2">
                        <button class="btn btn-sm btn-outline-warning flex-fill" onclick="fixSubs(true)">
                            <i class="bi bi-eye"></i> Önce Gör
                        </button>
                        <button class="btn btn-sm btn-danger flex-fill" onclick="fixSubs(false)">
                            <i class="bi bi-trash3"></i> Hataları Sil
                        </button>
                    </div>
                    <div id="fixSubResult" style="display:none;margin-top:8px;font-size:12px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px;font-family:monospace;white-space:pre-wrap;max-height:150px;overflow:auto"></div>
                </div>

                <hr style="border-color:var(--border);margin:10px 0">

                {{-- Re-queue --}}
                <div class="mb-2">
                    <div style="font-weight:600;color:var(--text);margin-bottom:6px">
                        <i class="bi bi-arrow-repeat" style="color:var(--info)"></i>
                        Yeniden Kuyruğa Al
                    </div>
                    <div style="color:var(--text2);font-size:12px;margin-bottom:8px">
                        Done job'ları tekrar pending yaparak botların her iki kaynaktan
                        <code>video_sources</code> eklemesini sağlar.
                    </div>
                    <div class="d-flex gap-2 mb-2">
                        <div style="flex:1">
                            <label style="font-size:11px;color:var(--text2)">Adet</label>
                            <input type="number" id="requeueLimit" class="form-control form-control-sm" value="50" min="1" max="500">
                        </div>
                    </div>
                    <div class="d-flex gap-2">
                        <button class="btn btn-sm btn-outline-info flex-fill" onclick="requeueAnizium()">
                            <i class="bi bi-cloud-arrow-down"></i> Anizium'u Yenile
                        </button>
                        <button class="btn btn-sm btn-outline-primary flex-fill" onclick="requeueAnimecix()">
                            <i class="bi bi-film"></i> AnimeCix'i Yenile
                        </button>
                    </div>
                    <div id="requeueResult" style="display:none;margin-top:8px;font-size:12px;padding:8px;background:var(--bg);border:1px solid var(--border);border-radius:6px"></div>
                </div>

            </div>
        </div>

        {{-- Yardım --}}
        <div class="card">
            <div class="card-header">
                <i class="bi bi-question-circle" style="color:var(--text2)"></i>
                <h6>Nasıl Kullanılır?</h6>
            </div>
            <div class="card-body" style="font-size:13px">
                <div style="font-size:12px;font-weight:700;color:var(--text);margin-bottom:6px">Çift Kaynak Akışı</div>
                <ol style="color:var(--text2);padding-left:18px;line-height:2;margin-bottom:10px">
                    <li>Local: <code>python reimport_all.py</code> çalıştır</li>
                    <li>Local: <code>python anizium_scraper/bot2_upload.py --daemon</code></li>
                    <li>Local: <code>python animecix_scraper/daemon.py</code></li>
                    <li>Her bölüm otomatik <strong>"4K"</strong> + <strong>çevirmen</strong> seçeneğiyle gelir</li>
                </ol>
                <div style="font-size:12px;font-weight:700;color:var(--text);margin-bottom:6px">CDN ID Nasıl Bulunur?</div>
                <ol style="color:var(--text2);padding-left:18px;line-height:2;margin-bottom:0">
                    <li>Anizium'da herhangi bir bölümü oynat</li>
                    <li>F12 → Network → <code>master.m3u8</code> ara</li>
                    <li>URL'den sayıyı al: <code style="color:var(--warning)">85937</code></li>
                </ol>
            </div>
        </div>

    </div>

    {{-- ── Sağ: Job Listesi ── --}}
    <div class="col-lg-7">
        <div class="card">
            <div class="card-header">
                <i class="bi bi-list-task" style="color:var(--info)"></i>
                <h6>Import Geçmişi</h6>
                <span style="font-size:12px;color:var(--text2)">{{ $jobs->total() }} job</span>
                <button class="btn btn-sm btn-outline-danger ms-auto" onclick="openBulkDelete()" title="Toplu Sil">
                    <i class="bi bi-trash3"></i> Toplu Sil
                </button>
            </div>

            {{-- Toplu silme paneli --}}
            <div id="bulkDeletePanel" style="display:none;padding:12px 16px;background:rgba(220,53,69,.06);border-bottom:1px solid rgba(220,53,69,.2)">
                <div style="font-size:12px;font-weight:700;color:var(--danger);margin-bottom:10px">
                    <i class="bi bi-exclamation-triangle"></i> Hangi joblar silinsin?
                </div>
                <div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px">
                    <label style="display:flex;align-items:center;gap:6px;font-size:13px;cursor:pointer">
                        <input type="checkbox" id="del-failed" checked> <span style="color:var(--danger)">Hatalı</span> <span id="cnt-failed" class="badge bg-danger ms-1">—</span>
                    </label>
                    <label style="display:flex;align-items:center;gap:6px;font-size:13px;cursor:pointer">
                        <input type="checkbox" id="del-pending"> <span style="color:var(--text2)">Bekleyen</span> <span id="cnt-pending" class="badge bg-secondary ms-1">—</span>
                    </label>
                    <label style="display:flex;align-items:center;gap:6px;font-size:13px;cursor:pointer">
                        <input type="checkbox" id="del-stuck"> <span style="color:var(--warning)">Takılı Kalan</span> <span id="cnt-stuck" class="badge bg-warning text-dark ms-1">—</span>
                        <span style="font-size:11px;color:var(--text2)">(2+ saat işlemde)</span>
                    </label>
                </div>
                <div style="display:flex;gap:8px;align-items:center">
                    <button class="btn btn-sm btn-danger" onclick="runBulkDelete()">
                        <i class="bi bi-trash3"></i> Seçilenleri Sil
                    </button>
                    <button class="btn btn-sm btn-secondary" onclick="document.getElementById('bulkDeletePanel').style.display='none'">
                        İptal
                    </button>
                    <span id="bulkDeleteMsg" style="font-size:12px;margin-left:4px"></span>
                </div>
            </div>
            <div class="card-body">
                @forelse($jobs as $job)
                <div class="job-card">
                    <div class="d-flex align-items-start justify-content-between gap-3 mb-2">
                        <div style="flex:1;min-width:0">
                            <div style="font-size:13.5px;font-weight:700;color:var(--text)" class="text-truncate">
                                {{ $job->anime_title ?: 'Anime CDN #'.$job->cdn_id }}
                            </div>
                            <div style="font-size:12px;color:var(--text2);margin-top:2px">
                                CDN: <code>{{ $job->cdn_id }}</code>
                                @if($job->season_ranges)
                                    &nbsp;·&nbsp;
                                    @foreach($job->season_ranges as $r)
                                        S{{ $r['season'] }} E{{ $r['from'] }}-{{ $r['to'] }}{{ !$loop->last ? ', ' : '' }}
                                    @endforeach
                                @endif
                            </div>
                        </div>
                        <div class="d-flex gap-2 align-items-center flex-shrink-0">
                            <span class="badge bg-{{ $job->status_color }}">{{ $job->status_label }}</span>
                            <a href="{{ route('admin.import.show',$job) }}" class="btn btn-sm btn-secondary">
                                <i class="bi bi-eye"></i>
                            </a>
                            <form method="POST" action="{{ route('admin.import.destroy',$job) }}"
                                  onsubmit="return confirm('Job silinsin mi?')">
                                @csrf @method('DELETE')
                                <button class="btn btn-sm btn-outline-danger"><i class="bi bi-trash3"></i></button>
                            </form>
                        </div>
                    </div>

                    @if($job->total_episodes > 0)
                    <div class="mb-2">
                        <div class="d-flex justify-content-between mb-1" style="font-size:12px;color:var(--text2)">
                            <span>{{ $job->done_episodes }}/{{ $job->total_episodes }} bölüm</span>
                            <span>%{{ $job->progress_percent }}</span>
                        </div>
                        <div class="progress" style="height:5px">
                            <div class="progress-bar" style="background:{{ $job->status_color==='success'?'var(--success)':($job->status_color==='danger'?'var(--danger)':'var(--accent)') }};width:{{ $job->progress_percent }}%"></div>
                        </div>
                    </div>
                    @endif

                    @if($job->current_step)
                    <div style="font-size:12px;color:var(--text2)">{{ $job->current_step }}</div>
                    @endif

                    <div style="font-size:11.5px;color:var(--text3);margin-top:4px">{{ $job->created_at->format('d.m.Y H:i') }}</div>
                </div>
                @empty
                <div class="empty-state">
                    <i class="bi bi-cloud-download"></i>
                    <h6>Henüz import job yok</h6>
                    <p>Sol panelden yeni bir import başlatın.</p>
                </div>
                @endforelse

                <div class="mt-3">
                    {{ $jobs->links('admin.partials.pagination') }}
                </div>
            </div>
        </div>
    </div>
</div>

@endsection

@push('scripts')
<script>
function showTestResult(text, ok=true) {
    const el = document.getElementById('testResult');
    el.style.display='block';
    el.style.color = ok ? 'var(--success)' : 'var(--danger)';
    el.textContent = text;
}
async function testApi() {
    showTestResult('Test ediliyor...', true);
    try {
        const r = await fetch('{{ url("/api/import/test") }}', {
            headers:{'X-Import-Key':'{{ config("app.import_api_key") }}','Accept':'application/json'}
        });
        const d = await r.json();
        if (d.ok) showTestResult(`✓ API bağlantısı başarılı\n  DB: ${d.db}\n  Toplam job: ${d.total}\n  Bekleyen: ${d.pending}`, true);
        else showTestResult('✗ API hatası: '+JSON.stringify(d), false);
    } catch(e) { showTestResult('✗ Bağlantı hatası: '+e.message, false); }
}
async function testCdn() {
    const cdnId = document.querySelector('[name="cdn_id"]').value.trim()||'85937';
    const url = `https://f.aniziumserver.sbs/${cdnId}/1/1/1080p-original/master.m3u8`;
    showTestResult(`CDN test ediliyor...\nURL: ${url}`, true);
    try {
        await fetch(url, {method:'HEAD',mode:'no-cors'});
        showTestResult(`✓ CDN erişilebilir (CDN ID: ${cdnId})\n${url}`, true);
    } catch(e) { showTestResult(`✗ CDN erişilemedi: ${e.message}`, false); }
}

let rangeIndex = {{ count(old('season_ranges',[[]])) }};
function addRange() {
    const row = document.createElement('div');
    row.className='range-row d-flex gap-2 mb-2 align-items-center';
    row.innerHTML=`
        <div style="flex:0 0 70px"><input type="number" name="season_ranges[${rangeIndex}][season]" class="form-control form-control-sm text-center" placeholder="S" min="1" value="1" required></div>
        <input type="number" name="season_ranges[${rangeIndex}][from]" class="form-control form-control-sm text-center" placeholder="Baş" min="1" style="flex:1">
        <span style="color:var(--text3);font-size:12px">—</span>
        <input type="number" name="season_ranges[${rangeIndex}][to]" class="form-control form-control-sm text-center" placeholder="Bit" min="1" style="flex:1">
        <button type="button" class="btn btn-sm btn-outline-danger" onclick="removeRange(this)"><i class="bi bi-trash3"></i></button>`;
    document.getElementById('rangeRows').appendChild(row);
    rangeIndex++;
}
function removeRange(btn) {
    if (document.querySelectorAll('.range-row').length<=1) return;
    btn.closest('.range-row').remove();
}

// ── Araçlar ──────────────────────────────────────────────────────────────────

const CSRF = document.querySelector('meta[name="csrf-token"]')?.content || '';

async function loadStats() {
    try {
        const r = await fetch('{{ route("admin.import.sourceStats") }}', {
            headers:{'Accept':'application/json','X-Requested-With':'XMLHttpRequest'}
        });
        const d = await r.json();
        document.getElementById('st-both').textContent  = d.episodes_with_both ?? '—';
        document.getElementById('st-aniz').textContent  = d.episodes_only_anizium ?? '—';
        document.getElementById('st-acix').textContent  = d.episodes_only_animecix ?? '—';
        document.getElementById('st-sub').textContent   = d.subtitle_mismatch ?? '—';
    } catch(e) { console.warn('stats error', e); }
}
loadStats(); // sayfa açılışında bir kez çek

async function fixSubs(dryRun) {
    const el = document.getElementById('fixSubResult');
    el.style.display = 'block';
    el.textContent   = 'İşleniyor...';
    try {
        const r = await fetch('{{ route("admin.import.fixSubtitles") }}', {
            method:'POST',
            headers:{'Accept':'application/json','Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
            body: JSON.stringify({dry_run: dryRun}),
        });
        const d = await r.json();
        if (dryRun) {
            el.textContent = `Kontrol edildi: ${d.checked}\nUyuşmazlık: ${d.mismatch}\n\n`
                + (d.details.map(x => `S${x.season}E${x.episode} ${x.lang}: name=${x.name} → beklenen=${x.expected}`).join('\n') || 'Hata bulunamadı.');
        } else {
            el.textContent = `Kontrol: ${d.checked}  •  Uyuşmazlık: ${d.mismatch}  •  Silindi: ${d.deleted}`;
            loadStats();
        }
    } catch(e) { el.textContent = 'Hata: ' + e.message; }
}

async function requeueAnizium() {
    const limit = document.getElementById('requeueLimit').value || 50;
    const el = document.getElementById('requeueResult');
    el.style.display = 'block';
    el.textContent   = 'İşleniyor...';
    try {
        const r = await fetch('{{ route("admin.import.requeueAnizium") }}', {
            method:'POST',
            headers:{'Accept':'application/json','Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
            body: JSON.stringify({limit: parseInt(limit)}),
        });
        const d = await r.json();
        el.innerHTML = `<span style="color:var(--success)">✓ Anizium: ${d.requeued} job yeniden kuyruğa alındı (${d.checked} kontrol edildi)</span>`;
    } catch(e) { el.textContent = 'Hata: ' + e.message; }
}

async function requeueAnimecix() {
    const limit = document.getElementById('requeueLimit').value || 50;
    const el = document.getElementById('requeueResult');
    el.style.display = 'block';
    el.textContent   = 'İşleniyor...';
    try {
        const r = await fetch('{{ route("admin.import.requeueAnimecix") }}', {
            method:'POST',
            headers:{'Accept':'application/json','Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
            body: JSON.stringify({limit: parseInt(limit)}),
        });
        const d = await r.json();
        el.innerHTML = `<span style="color:var(--success)">✓ AnimeCix: ${d.requeued} job yeniden kuyruğa alındı (${d.checked} kontrol edildi)</span>`;
    } catch(e) { el.textContent = 'Hata: ' + e.message; }
}

// ── Toplu Silme ──────────────────────────────────────────────────────────────

const BULK_COUNTS_URL = '{{ route("admin.import.bulkCounts") }}';
const BULK_DELETE_URL = '{{ route("admin.import.destroyByStatus") }}';

async function openBulkDelete() {
    const panel = document.getElementById('bulkDeletePanel');
    panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
    if (panel.style.display === 'block') loadBulkCounts();
}

async function loadBulkCounts() {
    try {
        const r = await fetch(BULK_COUNTS_URL, {headers:{'Accept':'application/json'}});
        const d = await r.json();
        document.getElementById('cnt-failed').textContent  = d.failed  ?? 0;
        document.getElementById('cnt-pending').textContent = d.pending ?? 0;
        document.getElementById('cnt-stuck').textContent   = d.stuck   ?? 0;
    } catch(e) {}
}

async function runBulkDelete() {
    const statuses = [];
    if (document.getElementById('del-failed').checked)  statuses.push('failed');
    if (document.getElementById('del-pending').checked) statuses.push('pending');
    if (document.getElementById('del-stuck').checked)   statuses.push('fetching','downloading','uploading');

    if (!statuses.length) { alert('En az bir kategori seç.'); return; }

    const names = [];
    if (document.getElementById('del-failed').checked)  names.push('hatalı');
    if (document.getElementById('del-pending').checked) names.push('bekleyen');
    if (document.getElementById('del-stuck').checked)   names.push('takılı kalan');

    if (!confirm(`${names.join(', ')} joblar silinsin mi? Bu işlem geri alınamaz.`)) return;

    const msgEl = document.getElementById('bulkDeleteMsg');
    msgEl.style.color = 'var(--text2)';
    msgEl.textContent = 'Siliniyor...';

    try {
        const r = await fetch(BULK_DELETE_URL, {
            method: 'DELETE',
            headers: {'Accept':'application/json','Content-Type':'application/json','X-CSRF-TOKEN':CSRF},
            body: JSON.stringify({ statuses, stuck_hours: 2 }),
        });
        const d = await r.json();
        if (d.ok) {
            msgEl.style.color = 'var(--success)';
            msgEl.textContent = `✓ ${d.deleted} job silindi.`;
            setTimeout(() => location.reload(), 1200);
        } else {
            msgEl.style.color = 'var(--danger)';
            msgEl.textContent = d.message || 'Hata oluştu.';
        }
    } catch(e) {
        msgEl.style.color = 'var(--danger)';
        msgEl.textContent = 'Sunucu hatası: ' + e.message;
    }
}
</script>
@endpush
