<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>OSS 冗余图片清理</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
    <style>
        :root {
            --primary: #4f46e5;
            --primary-hover: #4338ca;
            --bg: #f8fafc;
            --card: #ffffff;
            --text: #1e293b;
            --text-muted: #64748b;
            --border: #e2e8f0;
        }

        body { 
            background: var(--bg);
            font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
            color: var(--text);
            padding-bottom: 40px;
            margin: 0;
        }

        /* --- 导航栏优化 --- */
        .navbar {
            background: rgba(255, 255, 255, 0.85);
            backdrop-filter: blur(12px);
            border-bottom: 1px solid var(--border);
            box-shadow: 0 1px 2px rgba(0,0,0,0.03);
            z-index: 1000;
        }
        .navbar-brand { font-weight: 800; color: var(--primary) !important; display: flex; align-items: center; gap: 8px; }
        
        /* 移除所有按钮的焦点蓝框 */
        button:focus, .btn:focus, .form-check-input:focus, .form-control:focus {
            outline: none !important;
            box-shadow: none !important;
        }

        #deleteBtn:disabled { opacity: 0.5; cursor: not-allowed; filter: grayscale(1); }

        /* --- 网格与卡片 --- */
        .grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
            gap: 24px;
            padding: 24px 0;
        }
        .card {
            background: var(--card);
            border: 1px solid var(--border);
            border-radius: 14px;
            overflow: hidden;
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            position: relative;
        }
        .card:hover { transform: translateY(-4px); box-shadow: 0 12px 20px -5px rgba(0, 0, 0, 0.1); }
        .card.selected { border: 2px solid var(--primary); background: #f5f7ff; }
        .card.deleting { transform: scale(0.1); opacity: 0; pointer-events: none; }

        .img-area {
            position: relative;
            width: 100%;
            aspect-ratio: 16/9;
            background: #f1f5f9;
            overflow: hidden;
            cursor: pointer;
        }
        .img-area .placeholder {
            position: absolute; inset: 0; z-index: 10;
            display: flex; flex-direction: column; align-items: center; justify-content: center;
            gap: 8px; color: var(--text-muted); background: #f1f5f9;
            transition: opacity 0.3s; pointer-events: none;
        }
        .img-area img {
            position: absolute; top: 0; left: 0; width: 100%; height: 100%;
            object-fit: cover; z-index: 5; opacity: 0; transition: opacity 0.4s;
        }
        .img-area img.loaded { opacity: 1; }

        /* --- 配置弹窗设置 --- */
        .btn-browse { 
            background-color: #f1f5f9 !important; 
            border: 1px solid #dee2e6 !important; 
            color: #475569 !important;
            font-size: 0.85rem;
            font-weight: 500;
        }
        .btn-browse:hover { background-color: #e2e8f0 !important; }
        
        .modal-footer-custom {
            display: flex; justify-content: space-between; align-items: center;
            padding-top: 1.5rem; border-top: 1px solid var(--border);
        }

        /* --- 预览大图动画 --- */
        #viewer {
            border: none; background: transparent;
            width: 100vw; height: 100vh; max-width: 100vw; max-height: 100vh;
            padding: 0; margin: 0; overflow: hidden;
            opacity: 0; transform: scale(0.98);
            transition: opacity 0.25s ease, transform 0.25s ease;
            display: none; 
        }
        #viewer[open] { opacity: 1; transform: scale(1); display: flex; }
        #viewer::backdrop { background: rgba(15, 23, 42, 0.95); backdrop-filter: blur(10px); }

        .viewer-content { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; position: relative; }
        #viewImg { max-width: 92%; max-height: 92%; object-fit: contain; border-radius: 4px; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5); }

        /* 关闭按钮：居中、无蓝框、大图标 */
        .close-btn {
            position: absolute; top: 30px; right: 30px;
            background: transparent; color: white;
            border: none !important;
            width: 80px; height: 80px; cursor: pointer; z-index: 100;
            display: flex; align-items: center; justify-content: center;
            transition: all 0.2s;
            outline: none !important;
            box-shadow: none !important;
        }
        .close-btn i { font-size: 4rem; line-height: 1; }
        .close-btn:hover { transform: rotate(90deg); opacity: 0.8; }
        .close-btn:focus { border: none !important; outline: none !important; }

        .card-info { padding: 12px 16px; border-top: 1px solid var(--border); }
        .card-info .name { font-size: 0.85rem; font-weight: 600; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .empty { text-align: center; padding: 100px 20px; display: none; }
        .empty.show { display: block; }
    </style>
</head>
<body>
    <nav class="navbar sticky-top">
        <div class="container">
            <a class="navbar-brand" href="/">
                <i class="bi bi-images"></i> OSS Cleaner
            </a>
            
            <div class="d-flex align-items-center gap-2 gap-md-3">
                <span id="statInfo" class="text-muted small">
                    无用图片：<span class="text-danger fw-bold">{{ count }}</span>
                </span>
                
                <div class="vr mx-1"></div>

                <button class="btn btn-sm btn-light border shadow-none" onclick="config.showModal()">
                    <i class="bi bi-gear-fill"></i> <span class="d-none d-md-inline">设置</span>
                </button>
                
                <div class="form-check mb-0">
                    <input class="form-check-input shadow-none" type="checkbox" id="selectAll">
                    <label class="form-check-label small user-select-none" for="selectAll">全选</label>
                </div>
                
                <button class="btn btn-sm btn-danger px-3 shadow-none" id="deleteBtn" disabled>
                    <i class="bi bi-trash3-fill"></i> 删除
                </button>
            </div>
        </div>
    </nav>

    <div class="container mt-4">
        <dialog id="config" class="border-0 shadow-lg rounded-4" style="width: 90%; max-width: 650px;">
            <div class="p-4">
                <div class="d-flex justify-content-between align-items-center mb-4">
                    <h5 class="mb-0 fw-bold"><i class="bi bi-sliders me-2"></i>系统配置</h5>
                    <button class="btn-close shadow-none" onclick="config.close()"></button>
                </div>
                <form id="configForm" class="row g-3">
                    <div class="col-md-6"><label class="form-label small fw-bold">Access Key ID</label><input type="text" class="form-control form-control-sm shadow-none" name="ACCESS_KEY_ID" required></div>
                    <div class="col-md-6"><label class="form-label small fw-bold">Access Key Secret</label><input type="password" class="form-control form-control-sm shadow-none" name="ACCESS_KEY_SECRET" required></div>
                    <div class="col-12"><label class="form-label small fw-bold">Endpoint</label><input type="text" class="form-control form-control-sm shadow-none" name="ENDPOINT" placeholder="oss-cn-shanghai.aliyuncs.com" required></div>
                    <div class="col-md-6"><label class="form-label small fw-bold">Bucket Name</label><input type="text" class="form-control form-control-sm shadow-none" name="BUCKET_NAME" required></div>
                    <div class="col-md-6"><label class="form-label small fw-bold">OSS Domain (选填)</label><input type="text" class="form-control form-control-sm shadow-none" name="OSS_DOMAIN" placeholder="cdn.yourdomain.com"></div>
                    <div class="col-12">
                        <label class="form-label small fw-bold">Markdown Path</label>
                        <div class="input-group input-group-sm">
                            <input type="text" class="form-control shadow-none" name="MARKDOWN_PATH" id="markdownPath" readonly>
                            <button type="button" class="btn btn-browse px-3 shadow-none" id="folderBtn"><i class="bi bi-folder2-open me-1"></i> 浏览</button>
                        </div>
                    </div>
                    <div class="col-12"><label class="form-label small fw-bold">Prefix (目录前缀)</label><input type="text" class="form-control form-control-sm shadow-none" name="PREFIX" placeholder="images/"></div>
                </form>

                <div class="modal-footer-custom mt-4">
                    <div class="d-flex flex-column">
                        <button class="btn btn-sm btn-outline-primary px-3 shadow-none" id="testBtn">
                            <i class="bi bi-lightning-charge"></i> 测试连接
                        </button>
                        <div id="testMsg" class="small mt-1 fw-bold"></div>
                    </div>
                    <div class="d-flex gap-2 align-items-start">
                        <button class="btn btn-sm btn-light px-3 shadow-none" onclick="config.close()">取消</button>
                        <button class="btn btn-sm btn-primary px-4 shadow-none" id="saveBtn" disabled>保存配置</button>
                    </div>
                </div>
            </div>
        </dialog>

        <dialog id="viewer">
            <div class="viewer-content" onclick="closePreview()">
                <button class="close-btn" onclick="closePreview()">
                    <i class="bi bi-x"></i>
                </button>
                <img id="viewImg" src="" onclick="event.stopPropagation()">
            </div>
        </dialog>

        <div class="grid" id="imageGrid">
            {% for file in orphans %}
            <div class="card" data-key="{{ file.key }}">
                <div class="img-area" onclick="handleImgClick(this)" data-url="{{ file.url }}">
                    <div class="placeholder">
                        <i class="bi bi-eye fs-4"></i>
                        <span>预览图片</span>
                    </div>
                    <img src="" alt="preview">
                </div>
                
                <div class="card-info">
                    <span class="name" title="{{ file.name }}">{{ file.name }}</span>
                    <div class="d-flex justify-content-between align-items-center mt-2">
                        <div class="form-check">
                            <input class="form-check-input img-selector shadow-none" type="checkbox" value="{{ file.key }}" onchange="syncUI()">
                            <label class="small text-muted">选择</label>
                        </div>
                        <span class="badge bg-light text-dark border fw-normal size-badge">{{ file.size }}</span>
                    </div>
                </div>
            </div>
            {% endfor %}
        </div>

        <div id="emptyState" class="empty {% if count == 0 and not error %}show{% endif %}">
            <i class="bi bi-check2-all text-success" style="font-size: 4rem;"></i>
            <h4 class="mt-3 fw-bold">扫描完成</h4>
            <p class="text-muted">没有发现任何无用图片</p>
        </div>
    </div>

    <footer class="text-center py-4 text-muted small border-top mt-5">
        OSS Cleaner v{{ version }}
    </footer>

    <script>
        const $ = s => document.querySelector(s);
        const $$ = s => document.querySelectorAll(s);

        let testSuccess = false;
        const totalCount = {{ count }};

        // --- 1. 体积解析逻辑 (处理 0B 问题) ---
        function parseSize(text) {
            if (!text) return 0;
            const num = parseFloat(text);
            if (isNaN(num)) return 0;
            const unit = text.toLowerCase();
            if (unit.includes('kb')) return num * 1024;
            if (unit.includes('mb')) return num * 1024 * 1024;
            if (unit.includes('gb')) return num * 1024 * 1024 * 1024;
            return num;
        }

        function formatSize(bytes) {
            if (bytes === 0) return '0 B';
            const k = 1024;
            const sizes = ['B', 'KB', 'MB', 'GB'];
            const i = Math.floor(Math.log(bytes) / Math.log(k));
            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
        }

        function syncUI() {
            const selected = $$('.img-selector:checked');
            const deleteBtn = $('#deleteBtn');
            const statInfo = $('#statInfo');

            $$('.card').forEach(card => {
                const cb = card.querySelector('.img-selector');
                card.classList.toggle('selected', cb.checked);
            });

            deleteBtn.disabled = selected.length === 0;

            if (selected.length > 0) {
                let totalBytes = 0;
                selected.forEach(cb => {
                    const card = cb.closest('.card');
                    const badge = card.querySelector('.size-badge') || card.querySelector('.badge');
                    const sizeText = badge ? badge.innerText : '0';
                    totalBytes += parseSize(sizeText);
                });
                statInfo.innerHTML = `当前选中：<span class="text-primary fw-bold">${selected.length}</span> / ${totalCount} <span class="ms-1 badge bg-primary-subtle text-primary border-primary-subtle">${formatSize(totalBytes)}</span>`;
            } else {
                statInfo.innerHTML = `无用图片：<span class="text-danger fw-bold">${totalCount}</span>`;
            }
        }

        // --- 2. 两阶段点击逻辑 ---
        function handleImgClick(area) {
            const img = area.querySelector('img');
            const url = area.dataset.url;
            const placeholder = area.querySelector('.placeholder');

            // 如果已经加载成功，第二次点击才放大
            if (img.classList.contains('loaded')) {
                showPreview(url);
                return;
            }

            // 防止重复点击
            if (placeholder.querySelector('.spinner-border')) return;

            // 第一阶段：仅执行加载
            placeholder.innerHTML = `<div class="spinner-border spinner-border-sm text-primary"></div><span class="mt-1">加载中</span>`;

            const tempImg = new Image();
            tempImg.onload = () => {
                img.src = url;
                img.classList.add('loaded');
                placeholder.style.opacity = '0';
                setTimeout(() => {
                    placeholder.style.visibility = 'hidden';
                }, 300);
            };
            tempImg.src = url;
        }

        function showPreview(url) {
            const vImg = $('#viewImg');
            vImg.src = url;
            $('#viewer').showModal();
        }

        function closePreview() {
            $('#viewer').close();
            setTimeout(() => { $('#viewImg').src = ""; }, 300);
        }

        // --- 3. 配置校验与测试 ---
        $('#configForm').oninput = () => {
            testSuccess = false;
            $('#saveBtn').disabled = true;
            $('#testMsg').innerHTML = '';
        };

        $('#testBtn').onclick = async () => {
            const data = Object.fromEntries(new FormData($('#configForm')));
            const btn = $('#testBtn');
            const msg = $('#testMsg');
            
            btn.disabled = true;
            btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> 测试中';
            msg.innerHTML = '';

            try {
                const res = await fetch('/test-connection', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify(data)
                });
                const result = await res.json();
                if (result.status === 'success') {
                    msg.innerHTML = '<span class="text-success"><i class="bi bi-check-circle-fill"></i> 连接成功</span>';
                    testSuccess = true;
                    $('#saveBtn').disabled = false;
                } else {
                    msg.innerHTML = `<span class="text-danger"><i class="bi bi-x-circle-fill"></i> ${result.message}</span>`;
                }
            } catch (e) { 
                msg.innerHTML = '<span class="text-danger"><i class="bi bi-exclamation-triangle-fill"></i> 请求异常</span>';
            }
            finally {
                btn.disabled = false;
                btn.innerHTML = '<i class="bi bi-lightning-charge"></i> 测试连接';
            }
        };

        // --- 4. 批量删除 ---
        $('#deleteBtn').onclick = async () => {
            const selectedCbs = [...$$('.img-selector:checked')];
            const keys = selectedCbs.map(cb => cb.value);

            if (!confirm(`确定要永久删除这 ${keys.length} 张图片吗？`)) return;

            const delBtn = $('#deleteBtn');
            delBtn.disabled = true;
            delBtn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';

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

                if ((await res.json()).status === 'success') {
                    selectedCbs.forEach(cb => cb.closest('.card').classList.add('deleting'));
                    setTimeout(() => location.reload(), 500);
                }
            } catch (e) { alert('删除失败'); delBtn.disabled = false; }
        };

        // --- 基础事件 ---
        $('#selectAll').onchange = (e) => {
            $$('.img-selector').forEach(cb => cb.checked = e.target.checked);
            syncUI();
        };

        $('#saveBtn').onclick = async () => {
            const data = Object.fromEntries(new FormData($('#configForm')));
            await fetch('/config', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(data)
            });
            location.reload();
        };

        $('#folderBtn').onclick = async () => {
            const res = await fetch('/select-folder').then(r => r.json());
            if (res.status === 'success') {
                $('#markdownPath').value = res.path;
                $('#configForm').dispatchEvent(new Event('input'));
            }
        };

        window.onload = async () => {
            const res = await fetch('/config').then(r => r.json()).catch(() => ({}));
            Object.entries(res).forEach(([k, v]) => {
                if($('#configForm').elements[k]) $('#configForm').elements[k].value = v || '';
            });
            {% if error %} config.showModal(); {% endif %}
        };
    </script>
</body>
</html>