<?php
require_once dirname(__DIR__) . '/config/config.php';
require_once dirname(__DIR__) . '/includes/db.php';
require_once dirname(__DIR__) . '/includes/functions.php';
require_once dirname(__DIR__) . '/includes/auth.php';
require_once dirname(__DIR__) . '/includes/layout.php';
requirePermission('music_scan');

$pdo = getDBConnection();
$scanPath = getScanPathSetting();
$displayScanPath = maskInternalPathText($scanPath);
$winScanPath = resolveFilesystemPath($scanPath, 'readable_dir') ?? toWinPath($scanPath);
$dirExists = is_dir($winScanPath);
$allowedExtensions = getAllowedExtensionsSetting();
$getId3Available = initGetID3();

$totalSongs = (int)$pdo->query("SELECT COUNT(*) FROM songs WHERE is_missing = 0")->fetchColumn();
$allScannedSongs = (int)$pdo->query("SELECT COUNT(*) FROM songs")->fetchColumn();
$missingFiles = (int)$pdo->query("SELECT COUNT(*) FROM songs WHERE is_missing = 1")->fetchColumn();
$metadataMissing = (int)$pdo->query("
    SELECT COUNT(*) FROM songs
    WHERE is_missing = 0 AND (
        title IS NULL OR TRIM(title) = ''
        OR artist IS NULL OR TRIM(artist) = ''
        OR album IS NULL OR TRIM(album) = ''
        OR genre IS NULL OR TRIM(genre) = ''
        OR year IS NULL OR TRIM(year) = ''
        OR duration IS NULL OR duration <= 0
        OR cover_hash IS NULL OR TRIM(cover_hash) = ''
    )
")->fetchColumn();

$lastScanStmt = $pdo->query("
    SELECT id, scan_started_at, scan_finished_at, total_found, new_count, updated_count, deleted_count,
           skipped_count, tag_count, filename_count, manual_protected_count, cover_success_count,
           cover_missing_count, metadata_error_count, missing_count, message, created_at
    FROM scan_logs
    WHERE scan_finished_at IS NOT NULL
    ORDER BY id DESC LIMIT 1
");
$lastScan = $lastScanStmt->fetch();
$recentLogs = $pdo->query("
    SELECT id, scan_started_at, scan_finished_at, total_found, new_count, updated_count, deleted_count,
           skipped_count, tag_count, filename_count, manual_protected_count, cover_success_count,
           cover_missing_count, metadata_error_count, missing_count, message, created_at
    FROM scan_logs
    ORDER BY id DESC LIMIT 10
")->fetchAll();

$errorLogs = [];
$logFilePath = dirname(__DIR__) . '/storage/logs/scan.log';
if (file_exists($logFilePath)) {
    $logLines = file($logFilePath);
    if ($logLines) {
        foreach (array_reverse($logLines) as $line) {
            if (strpos($line, '[WARNING]') !== false || strpos($line, '[ERROR]') !== false) {
                $errorLogs[] = trim($line);
                if (count($errorLogs) >= 8) break;
            }
        }
    }
}

$autoScanEnabled = settingBool('scan_auto_enabled', true);
$autoScanIntervalSeconds = settingInt('scan_auto_interval_minutes', 10, 1, 1440) * 60;
$shouldAutoScan = false;
$secondsSinceLastScan = 999999;
if ($dirExists) {
    if (!$lastScan) {
        $shouldAutoScan = $autoScanEnabled;
    } else {
        $secondsSinceLastScan = max(0, time() - strtotime($lastScan['scan_finished_at']));
        $shouldAutoScan = $autoScanEnabled && $secondsSinceLastScan >= $autoScanIntervalSeconds;
    }
}

function scanLogElapsedLabel($log) {
    if (empty($log['scan_started_at']) || empty($log['scan_finished_at'])) return '-';
    $seconds = max(0, strtotime($log['scan_finished_at']) - strtotime($log['scan_started_at']));
    if ($seconds < 60) return $seconds . '초';
    return floor($seconds / 60) . '분 ' . ($seconds % 60) . '초';
}

function scanCountValue($row, $key) {
    return number_format((int)($row[$key] ?? 0));
}

$scanModes = [
    'quick' => [
        'title' => '빠른 스캔',
        'icon' => 'fa-bolt',
        'description' => '새 파일과 변경된 파일만 확인합니다. 평소에는 이 모드를 사용하세요.',
        'button' => '빠른 스캔 시작',
    ],
    'metadata' => [
        'title' => '메타데이터 갱신',
        'icon' => 'fa-tags',
        'description' => '기존 곡도 다시 분석해 누락된 태그와 앨범아트를 보강합니다.',
        'button' => '메타데이터 갱신',
    ],
    'force' => [
        'title' => '강제 재분석',
        'icon' => 'fa-triangle-exclamation',
        'description' => '파일 내부 태그로 강제 갱신합니다. 수동 수정값이 바뀔 수 있습니다.',
        'button' => '강제 재분석',
    ],
];

renderHeader('스캔 관리', 'scan');
?>
<div class="admin-dashboard scan-admin-page"
     data-scan-page
     data-scan-endpoint="../scan.php"
     data-auto-scan="<?php echo $shouldAutoScan && $dirExists ? '1' : '0'; ?>">
    <div class="page-title-section scan-page-title">
        <div>
            <h1 class="page-main-title">음악 스캔 관리</h1>
            <p class="page-subtitle">D드라이브 음악 폴더를 스캔해 새 곡, 누락 파일, 메타데이터 상태를 빠르게 갱신합니다.</p>
        </div>
        <div class="page-title-actions">
            <a class="btn btn-primary" href="music_upload.php"><i class="fa-solid fa-cloud-arrow-up"></i> 음악 업로드</a>
            <a class="btn btn-secondary" href="../settings.php"><i class="fas fa-sliders"></i> 스캔 설정</a>
        </div>
    </div>

    <?php if (!$dirExists): ?>
        <div class="alert-box alert-danger">
            <div class="alert-icon"><i class="fas fa-exclamation-triangle"></i></div>
            <div class="alert-content">
                <h3>설정된 음악 폴더를 찾을 수 없습니다.</h3>
                <p>관리자 설정의 음악 폴더 경로를 확인하세요.</p>
                <p class="current-path-info">현재 설정값: <span><?php echo h($displayScanPath); ?></span></p>
            </div>
        </div>
    <?php else: ?>
        <?php if ($shouldAutoScan): ?>
            <div class="alert-box alert-info" id="auto-scan-banner">
                <div class="alert-icon"><i class="fas fa-magic spinner-icon"></i></div>
                <div class="alert-content">
                    <h3>자동 스캔이 준비되었습니다.</h3>
                    <p>페이지가 열리면 빠른 스캔을 한 번 실행합니다. 재생 중인 음악은 유지됩니다.</p>
                </div>
            </div>
        <?php endif; ?>

        <div class="dashboard-grid scan-overview-grid">
            <div class="stats-card scan-path-card">
                <div class="card-icon"><i class="fas fa-folder-open"></i></div>
                <div class="card-info">
                    <span class="card-label">스캔 대상</span>
                    <span class="card-value path-value" title="<?php echo h($displayScanPath); ?>"><?php echo h($displayScanPath); ?></span>
                    <small><?php echo h(implode(', ', $allowedExtensions)); ?></small>
                </div>
            </div>
            <div class="stats-card">
                <div class="card-icon"><i class="fas fa-music"></i></div>
                <div class="card-info">
                    <span class="card-label">사용 가능 곡</span>
                    <span class="card-value"><?php echo number_format($totalSongs); ?>곡</span>
                    <small>파일이 실제 존재하는 곡</small>
                </div>
            </div>
            <div class="stats-card">
                <div class="card-icon"><i class="fas fa-database"></i></div>
                <div class="card-info">
                    <span class="card-label">DB 등록 곡</span>
                    <span class="card-value"><?php echo number_format($allScannedSongs); ?>곡</span>
                    <small>파일 없음 항목 포함</small>
                </div>
            </div>
            <a class="stats-card stats-card-link" href="missing_files.php">
                <div class="card-icon"><i class="fas fa-link-slash"></i></div>
                <div class="card-info">
                    <span class="card-label">파일 없음</span>
                    <span class="card-value"><?php echo number_format($missingFiles); ?>곡</span>
                    <small>정리 또는 복구 필요</small>
                </div>
            </a>
            <a class="stats-card stats-card-link" href="metadata_quality.php">
                <div class="card-icon"><i class="fas fa-triangle-exclamation"></i></div>
                <div class="card-info">
                    <span class="card-label">품질 경고</span>
                    <span class="card-value"><?php echo number_format($metadataMissing); ?>곡</span>
                    <small>태그/아트 누락 포함</small>
                </div>
            </a>
            <div class="stats-card">
                <div class="card-icon"><i class="fas fa-compact-disc"></i></div>
                <div class="card-info">
                    <span class="card-label">getID3</span>
                    <span class="card-value"><?php echo $getId3Available ? '사용 가능' : 'fallback'; ?></span>
                    <small><?php echo $getId3Available ? '파일 내부 태그 분석 가능' : '파일명/폴더명 분석으로 동작'; ?></small>
                </div>
            </div>
        </div>

        <section class="scan-action-section scan-runner">
            <div class="scan-status-summary">
                <h2>스캔 실행</h2>
                <p class="scan-msg" id="scan-status-message">
                    <?php echo $lastScan ? h(scanMessageToKorean($lastScan['message'])) : '아직 스캔 기록이 없습니다.'; ?>
                </p>
                <?php if (!$shouldAutoScan && $lastScan && $autoScanEnabled): ?>
                    <span class="scan-countdown-info">
                        <i class="fas fa-info-circle"></i>
                        다음 자동 스캔까지 약 <strong><?php echo max(1, ceil(($autoScanIntervalSeconds - $secondsSinceLastScan) / 60)); ?>분</strong>
                    </span>
                <?php endif; ?>
            </div>

            <div class="scan-mode-grid">
                <?php foreach ($scanModes as $mode => $item): ?>
                    <article class="scan-mode-card <?php echo $mode === 'force' ? 'scan-mode-danger' : ''; ?>">
                        <i class="fas <?php echo h($item['icon']); ?>"></i>
                        <strong><?php echo h($item['title']); ?></strong>
                        <p><?php echo h($item['description']); ?></p>
                        <button type="button"
                                class="btn <?php echo $mode === 'quick' ? 'btn-primary' : 'btn-secondary'; ?>"
                                data-scan-mode="<?php echo h($mode); ?>">
                            <?php echo h($item['button']); ?>
                        </button>
                    </article>
                <?php endforeach; ?>
            </div>

            <div class="scan-live-panel" id="scan-live-panel" hidden>
                <div class="scan-live-head">
                    <strong id="scan-live-title">스캔 대기 중</strong>
                    <span id="scan-live-elapsed">-</span>
                </div>
                <div class="scan-progress-track" aria-hidden="true"><span id="scan-progress-bar"></span></div>
                <div class="scan-result-grid" id="scan-result-grid"></div>
                <div class="scan-live-actions">
                    <button type="button" class="btn btn-secondary btn-sm" id="scan-refresh-page">화면 수치 갱신</button>
                </div>
            </div>
        </section>

        <section class="logs-section scan-guide-section">
            <h2 class="section-title"><i class="fas fa-circle-info title-icon"></i> 빠르게 스캔하는 기준</h2>
            <div class="scan-guide-grid">
                <div>
                    <strong>빠른 스캔</strong>
                    <p>파일 크기와 수정 시간이 같으면 건너뜁니다. 가장 빠르고 평소 사용에 적합합니다.</p>
                </div>
                <div>
                    <strong>메타데이터 갱신</strong>
                    <p>앨범아트나 태그가 누락된 곡을 보강할 때 사용합니다. 수동 보호 설정은 유지됩니다.</p>
                </div>
                <div>
                    <strong>강제 재분석</strong>
                    <p>파일 내부 태그를 기준으로 다시 씁니다. 실행 전 수동 수정값 덮어쓰기 가능성을 확인하세요.</p>
                </div>
            </div>
        </section>

        <section class="logs-section">
            <h2 class="section-title"><i class="fas fa-list-alt title-icon"></i> 최근 스캔 기록</h2>
            <div class="table-container scan-log-table-wrap">
                <table class="data-table scan-log-table">
                    <thead>
                        <tr>
                            <th>ID</th>
                            <th>완료</th>
                            <th>소요</th>
                            <th>발견</th>
                            <th>신규</th>
                            <th>갱신</th>
                            <th>건너뜀</th>
                            <th>파일 없음</th>
                            <th>오류</th>
                            <th>메시지</th>
                        </tr>
                    </thead>
                    <tbody>
                        <?php if (empty($recentLogs)): ?>
                            <tr class="scan-empty-row"><td colspan="10" class="text-center">최근 스캔 기록이 없습니다.</td></tr>
                        <?php else: ?>
                            <?php foreach ($recentLogs as $log): ?>
                                <tr>
                                    <td data-label="ID"><?php echo h($log['id']); ?></td>
                                    <td data-label="완료"><?php echo h($log['scan_finished_at'] ?? '-'); ?></td>
                                    <td data-label="소요"><?php echo h(scanLogElapsedLabel($log)); ?></td>
                                    <td data-label="발견"><?php echo scanCountValue($log, 'total_found'); ?></td>
                                    <td data-label="신규" class="text-success"><?php echo scanCountValue($log, 'new_count'); ?></td>
                                    <td data-label="갱신" class="text-info"><?php echo scanCountValue($log, 'updated_count'); ?></td>
                                    <td data-label="건너뜀"><?php echo scanCountValue($log, 'skipped_count'); ?></td>
                                    <td data-label="파일 없음" class="text-warning"><?php echo scanCountValue($log, 'deleted_count'); ?></td>
                                    <td data-label="오류" class="<?php echo (int)($log['metadata_error_count'] ?? 0) > 0 ? 'text-warning' : ''; ?>"><?php echo scanCountValue($log, 'metadata_error_count'); ?></td>
                                    <td data-label="메시지" class="log-message-td"><?php echo h(scanMessageToKorean($log['message'])); ?></td>
                                </tr>
                            <?php endforeach; ?>
                        <?php endif; ?>
                    </tbody>
                </table>
            </div>
        </section>

        <section class="logs-section">
            <h2 class="section-title"><i class="fas fa-exclamation-circle title-icon"></i> 최근 스캔 오류</h2>
            <div class="error-log-console">
                <?php if (empty($errorLogs)): ?>
                    <p class="empty-text">최근 스캔 오류가 없습니다.</p>
                <?php else: ?>
                    <?php foreach ($errorLogs as $err): ?>
                        <div><?php echo h(scanMessageToKorean($err)); ?></div>
                    <?php endforeach; ?>
                <?php endif; ?>
            </div>
        </section>
    <?php endif; ?>
</div>

<script>
(function () {
    function initScanPage() {
        const page = document.querySelector('[data-scan-page]');
        if (!page || page.dataset.scanBound === '1') return;
        page.dataset.scanBound = '1';

        const endpoint = page.dataset.scanEndpoint || '../scan.php';
        const buttons = Array.from(page.querySelectorAll('[data-scan-mode]'));
        const livePanel = page.querySelector('#scan-live-panel');
        const liveTitle = page.querySelector('#scan-live-title');
        const liveElapsed = page.querySelector('#scan-live-elapsed');
        const progressBar = page.querySelector('#scan-progress-bar');
        const resultGrid = page.querySelector('#scan-result-grid');
        const statusMessage = page.querySelector('#scan-status-message');
        const refreshButton = page.querySelector('#scan-refresh-page');
        let running = false;
        let startedAt = 0;
        let timer = null;

        const labels = {
            total: '발견',
            new: '신규',
            updated: '갱신',
            skipped: '건너뜀',
            deleted: '파일 없음',
            errors: '파일 오류',
            tag: '태그 분석',
            filename: '파일명 분석',
            manual_protected: '수동 보호',
            cover: '앨범아트 있음',
            no_cover: '앨범아트 없음',
            metadata_errors: '메타데이터 오류',
            encoding_fixed: '인코딩 보정'
        };

        function clearCoverRuntimeCaches() {
            const jobs = [];
            if (navigator.serviceWorker && navigator.serviceWorker.controller) {
                try { navigator.serviceWorker.controller.postMessage({ type: 'CLEAR_RUNTIME_CACHES' }); } catch (err) {}
            }
            if (window.caches && typeof caches.keys === 'function') {
                jobs.push(
                    caches.keys()
                        .then(keys => Promise.all(keys
                            .filter(key => key.indexOf('melonlite-pwa-') === 0 && key.indexOf('-covers') !== -1)
                            .map(key => caches.delete(key))))
                        .catch(() => undefined)
                );
            }
            return Promise.all(jobs).then(() => undefined);
        }

        function setRunning(isRunning, modeLabel) {
            running = isRunning;
            buttons.forEach(button => {
                button.disabled = isRunning;
                button.classList.toggle('loading', isRunning);
            });
            if (livePanel) livePanel.hidden = false;
            if (liveTitle) liveTitle.textContent = isRunning ? `${modeLabel} 진행 중` : `${modeLabel} 완료`;
            if (progressBar) progressBar.style.width = isRunning ? '58%' : '100%';
            if (isRunning) {
                startedAt = Date.now();
                clearInterval(timer);
                timer = setInterval(() => {
                    if (!liveElapsed) return;
                    const seconds = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
                    liveElapsed.textContent = seconds < 60 ? `${seconds}초 경과` : `${Math.floor(seconds / 60)}분 ${seconds % 60}초 경과`;
                }, 500);
            } else {
                clearInterval(timer);
                timer = null;
            }
        }

        function renderStats(stats) {
            if (!resultGrid) return;
            const safeStats = stats || {};
            resultGrid.innerHTML = Object.keys(labels).map(key => {
                const value = Number(safeStats[key] || 0).toLocaleString('ko-KR');
                return `<div><span>${labels[key]}</span><strong>${value}</strong></div>`;
            }).join('');
        }

        function refreshPageStats() {
            if (window.MelonLiteNavigate) {
                window.MelonLiteNavigate(new URL(window.location.href), { push: false });
            } else {
                window.location.reload();
            }
        }

        function runScan(mode, autoStarted) {
            if (running) return;
            const button = page.querySelector(`[data-scan-mode="${mode}"]`);
            const modeLabel = button ? button.textContent.trim() : '스캔';
            if (mode === 'force' && !autoStarted && !confirm('강제 재분석은 수동 수정한 메타데이터를 바꿀 수 있습니다. 계속할까요?')) {
                return;
            }

            const formData = new FormData();
            formData.append('scan_mode', mode);
            if (window.APP_CSRF_TOKEN) formData.append('csrf_token', window.APP_CSRF_TOKEN);

            setRunning(true, modeLabel);
            renderStats({});
            if (statusMessage) statusMessage.textContent = `${modeLabel}을 실행하고 있습니다.`;

            fetch(endpoint, {
                method: 'POST',
                headers: {
                    'Accept': 'application/json',
                    'X-CSRF-Token': window.APP_CSRF_TOKEN || ''
                },
                body: formData,
                cache: 'no-store',
                credentials: 'same-origin'
            })
                .then(response => response.json().catch(() => {
                    throw new Error('스캔 응답을 JSON으로 읽을 수 없습니다.');
                }).then(data => {
                    if (!response.ok) throw new Error(data.message || `HTTP 오류 ${response.status}`);
                    return data;
                }))
                .then(data => {
                    renderStats(data.stats || {});
                    if (statusMessage) statusMessage.textContent = data.message || '스캔이 완료되었습니다.';
                    if (liveTitle) liveTitle.textContent = data.success ? `${modeLabel} 완료` : `${modeLabel} 완료, 확인 필요`;
                    return clearCoverRuntimeCaches();
                })
                .catch(error => {
                    console.error('Scan Error:', error);
                    if (statusMessage) statusMessage.textContent = '스캔 처리 중 오류가 발생했습니다: ' + error.message;
                    if (liveTitle) liveTitle.textContent = '스캔 실패';
                    if (progressBar) progressBar.style.width = '100%';
                })
                .finally(() => {
                    setRunning(false, modeLabel);
                });
        }

        buttons.forEach(button => {
            button.addEventListener('click', () => runScan(button.dataset.scanMode || 'quick', false));
        });
        if (refreshButton) refreshButton.addEventListener('click', refreshPageStats);

        if (page.dataset.autoScan === '1' && page.dataset.autoStarted !== '1') {
            page.dataset.autoStarted = '1';
            setTimeout(() => runScan('quick', true), 500);
        }
    }

    window.MelonLiteInitScanPage = initScanPage;
    if (!window.__MELON_LITE_SCAN_PAGE_BOUND) {
        window.__MELON_LITE_SCAN_PAGE_BOUND = true;
        document.addEventListener('melonlite:page-ready', initScanPage);
        document.addEventListener('DOMContentLoaded', initScanPage);
    }
    if (document.readyState !== 'loading') initScanPage();
})();
</script>
<?php renderFooter(); ?>
