<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <meta charset="UTF-8">
  <style>
    :root{--navy:#132238;--blue:#2979ff;--text:#172033;--muted:#6b7890;--red:#d9363e;--amber:#e39b18;--green:#18855b}
    *{box-sizing:border-box}body{margin:0;padding:16px;color:var(--text);font:13px Arial,sans-serif;background:linear-gradient(145deg,#edf4ff,#f8fbff 48%,#eef9f8)}
    .hero{padding:18px;color:#fff;border-radius:18px;background:radial-gradient(circle at 90% 10%,#2f87ff 0,transparent 35%),linear-gradient(135deg,#101d31,#193c66);box-shadow:0 12px 32px rgba(19,34,56,.22)}
    .hero h1{margin:0 0 6px;font-size:21px}.hero p{margin:0;color:#d8e8ff;line-height:1.45}.status-dot{display:inline-block;width:9px;height:9px;margin-right:6px;border-radius:50%;background:#67e8b7;box-shadow:0 0 12px #67e8b7}
    .card{margin-top:12px;padding:15px;border:1px solid #dfe8f3;border-radius:16px;background:rgba(255,255,255,.94);box-shadow:0 8px 24px rgba(50,75,110,.08)}
    label{display:block;margin:11px 0 5px;color:#45536a;font-weight:700}select,input{width:100%;padding:10px 11px;color:#172033;border:1px solid #cdd8e7;border-radius:10px;outline:0;background:#fff}select:focus,input:focus{border-color:var(--blue);box-shadow:0 0 0 3px rgba(41,121,255,.12)}
    .grid{display:grid;grid-template-columns:1fr 1fr;gap:9px}.mode{display:grid;grid-template-columns:1fr 1fr;gap:8px}.mode label{margin:0;padding:10px;border:1px solid #d9e3f0;border-radius:11px;font-weight:400;cursor:pointer}.mode input,.check input{width:auto;vertical-align:middle}.check{padding:10px;margin-top:10px;border-radius:11px;background:#eef5ff;border:1px solid #cfe0fa}.check label{margin:0;cursor:pointer}
    button{width:100%;padding:11px;border:0;border-radius:11px;cursor:pointer;font-weight:700;transition:.18s}button:hover{transform:translateY(-1px)}button:disabled{cursor:not-allowed;opacity:.55;transform:none}.primary{color:#fff;background:linear-gradient(135deg,#2979ff,#165bc8);box-shadow:0 8px 18px rgba(41,121,255,.25)}.secondary{color:#28405f;background:#eaf1fa}.danger{color:#b12830;background:#fdebed}.clear{margin-top:10px;color:#8a2530;border:1px solid #f3cbd0;background:#fff0f2}.buttons{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px}
    .progress{height:10px;margin:11px 0 7px;overflow:hidden;border-radius:20px;background:#e6edf6}.bar{width:0;height:100%;background:linear-gradient(90deg,#36c5f0,#2979ff);transition:width .35s}.row{display:flex;align-items:center;justify-content:space-between;gap:10px}.muted{color:var(--muted)}.stats{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:11px}.stat{padding:10px;border-radius:12px;background:#f4f7fb}.stat b{display:block;margin-top:3px;font-size:19px}.clean-stat b{color:var(--green)}.warning b{color:var(--amber)}.critical b{color:var(--red)}.errors b{color:#667085}
    .note{color:#5e6b7e;font-size:12px;line-height:1.45}.background-note{margin-top:10px;padding:10px;color:#27577e;border:1px solid #cbe1f5;border-radius:10px;background:#eef8ff;font-size:12px;line-height:1.45}.toast{display:none;margin-top:10px;padding:11px;border-radius:10px;line-height:1.45;background:#fff2d8;color:#7c5310}.toast.success{background:#dcf6e9;color:#12613f}.toast.error{background:#fde8ea;color:#952c35}.spinner{display:none;width:14px;height:14px;border:2px solid #bcd3f5;border-top-color:#2979ff;border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}
    details.ai{margin:12px 0;padding:12px;border:1px solid #d7e2f2;border-radius:13px;background:#f7faff}details.ai summary{cursor:pointer;color:#173b70;font-weight:700;list-style:none}details.ai summary::-webkit-details-marker{display:none}.ai-status{margin:9px 0 0;padding:8px 10px;border-radius:9px;color:#5e6b7e;background:#edf2f8;font-size:12px}.ai-status.ready{color:#12613f;background:#dcf6e9}.small-buttons{display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;margin-top:9px}.small-buttons button{padding:9px 5px;font-size:11px}.ai-enable{margin-top:10px;padding:10px;border:1px solid #c8ddff;border-radius:10px;background:#eaf3ff}.ai-enable label{margin:0;color:#173b70;cursor:pointer}.ai-enable input{width:auto;vertical-align:middle}
  </style>
</head>
<body>
  <section class="hero"><h1>🕰️ Web Archive 5.8.2</h1><p><span class="status-dot"></span>Фонова перевірка будь-якої кількості доменів.</p></section>

  <section class="card">
    <div class="row"><strong>Налаштування запуску</strong><span id="spinner" class="spinner"></span></div>
    <label for="sheet">Аркуш із доменами</label><select id="sheet" onchange="loadColumns()"></select>
    <label for="column">Колонка з доменами</label><select id="column"></select>
    <div class="grid">
      <div><label for="startRow">Почати з рядка</label><input id="startRow" type="number" min="2" value="2"></div>
      <div><label for="maxDomains">Кількість</label><input id="maxDomains" type="number" min="1" value="300"></div>
    </div>
    <div class="check"><label><input id="scanAll" type="checkbox" onchange="toggleScanAll()"> Сканувати всі домени до кінця аркуша</label></div>
    <label for="redirectYears">Період історичних редиректів (глибокий режим)</label>
    <select id="redirectYears"><option value="0">Уся доступна історія</option><option value="2">Останні 2 роки</option><option value="5">Останні 5 років</option><option value="10">Останні 10 років</option></select>
    <label>Режим аналізу</label>
    <div class="mode">
      <label><input type="radio" name="mode" value="quick"> ⚡ Швидкий<br><span class="muted">URL та історія</span></label>
      <label><input type="radio" name="mode" value="deep" checked> 🔬 Глибокий<br><span class="muted">URL, Title і текст</span></label>
    </div>
    <p class="note">Швидкий режим оцінює URL без читання сторінок. Глибокий читає спочатку до 6 знімків; за тематичними сигналами — до 8 (до 14 кандидатів) і перевіряє історичні 3xx. Це вибірковий аудит: неповні дані позначаються окремо.</p>
    <button id="startButton" class="primary" onclick="startAnalysis()">🚀 Запустити фонову перевірку</button>
    <div class="buttons"><button id="resumeButton" class="secondary" onclick="resumeAnalysis()">▶ Відновити</button><button class="danger" onclick="stopAnalysis()">■ Зупинити</button></div>
    <button id="clearButton" class="clear" onclick="clearResults()">🗑️ Очистити аналіз і докази</button>
    <div class="background-note">✅ Після запуску таблицю і браузер можна закрити. Перевірка продовжуватиметься автоматично у фоновому режимі.</div>
    <details class="ai"><summary>Тематичні правила та бали</summary><p class="note">100 — відхилити; 60–79 — сильні ознаки; 25–79 — згадки в HTML; 15–79 — URL. Це бали відбору, не відсоток спаму. Казино завжди заборонене. Збережені статуси діють для наступних перевірок, зокрема після відновлення. Готові результати не перераховуються. Для зміни статусів зупини перевірку.</p><div id="topicRules"></div><button id="savePolicyButton" class="primary" style="margin-top:12px" onclick="savePolicy()">💾 Зберегти статуси</button><p id="policyMessage" class="note" role="status" aria-live="polite">Завантаження статусів…</p></details><div id="toast" class="toast"></div>
  </section>

  <section class="card">
    <div class="row"><strong>Прогрес</strong><span id="state" class="muted">Очікування</span></div>
    <div class="progress"><div id="bar" class="bar"></div></div>
    <div class="row"><span id="message" class="muted">Готово до запуску</span><strong id="count">0 / 0</strong></div>
    <div class="stats">
      <div class="stat clean-stat">Без сигналів<b id="clean">0</b></div><div class="stat warning">Потребують перевірки<b id="warning">0</b></div>
      <div class="stat critical">Не підходять / критичні<b id="critical">0</b></div><div class="stat errors">Без висновку / помилки<b id="errors">0</b></div>
    </div>
    <p id="lastRow" class="note">Останній оброблений рядок: —</p>
  </section>

  <script>
    let refreshTimer=null;
    const el=id=>document.getElementById(id);
    function setBusy(v){el('spinner').style.display=v?'inline-block':'none'}
    function hideMessage(){el('toast').style.display='none';el('toast').className='toast'}
    function showMessage(message,type){const t=el('toast');t.className='toast '+(type||'');t.textContent=message;t.style.display='block'}
    function handleError(error){setBusy(false);showMessage('❌ '+(error&&error.message?error.message:String(error)),'error')}
    function toggleScanAll(){el('maxDomains').disabled=el('scanAll').checked}

    function initializePanel(){
      setBusy(true);
      google.script.run.withSuccessHandler(data=>{
        const select=el('sheet');select.innerHTML='';
        data.sheets.forEach(sheet=>{const o=document.createElement('option');o.value=sheet.name;o.textContent=sheet.name+' ('+sheet.lastRow+' рядків)';if(sheet.name===data.activeSheet)o.selected=true;select.appendChild(o)});
        fillColumns(data.columns);renderStatus(data.job);setBusy(false);startPolling();
      }).withFailureHandler(handleError).getWaybackSetupData();
    }

    function loadColumns(){setBusy(true);google.script.run.withSuccessHandler(columns=>{fillColumns(columns);setBusy(false)}).withFailureHandler(handleError).getWaybackColumns(el('sheet').value)}
    function fillColumns(columns){
      const select=el('column');select.innerHTML='';let likely=null;
      columns.forEach(column=>{const o=document.createElement('option');o.value=column.index;o.textContent=column.letter+' — '+column.header+(column.likelyDomain?' ★':'');select.appendChild(o);if(column.likelyDomain&&likely===null)likely=column.index});
      if(likely!==null)select.value=likely;
    }

    function startAnalysis(){
      hideMessage();
      const config={sheetName:el('sheet').value,domainColumn:Number(el('column').value),startRow:Number(el('startRow').value),maxDomains:Number(el('maxDomains').value),scanAll:el('scanAll').checked,mode:document.querySelector('input[name="mode"]:checked').value,aiEnabled:false,aiFallback:true,topicPolicy:readPolicy(),redirectYears:Number(el('redirectYears').value)};
      if(!config.scanAll&&config.maxDomains<1){showMessage('❌ Вкажи кількість доменів.','error');return}
      const text=config.scanAll?'усі домени до кінця аркуша':config.maxDomains+' доменів';
      if(!confirm('Запустити фонову перевірку: '+text+'?\nАвтоматичний бот без ШІ\n\nПісля запуску таблицю можна закрити.'))return;
      setBusy(true);el('startButton').disabled=true;
      google.script.run.withSuccessHandler(job=>{renderStatus(job);setBusy(false);startPolling();showMessage('✅ Фонову чергу створено. Таблицю можна закрити.','success')}).withFailureHandler(error=>{el('startButton').disabled=false;handleError(error)}).startWaybackAnalysis(config);
    }

    function stopAnalysis(){if(!confirm('Зупинити фонову перевірку? Прогрес буде збережено.'))return;setBusy(true);google.script.run.withSuccessHandler(job=>{renderStatus(job);setBusy(false);showMessage('Перевірку зупинено. Прогрес збережено.','')}).withFailureHandler(handleError).stopWaybackAnalysis(true)}
    function clearResults(){if(!confirm('Очистити дані у вкладках аналізу й доказів: «Web Archive — Аналіз» та «Web Archive — Докази»?\n\nЗаголовки й інші аркуші залишаться. Результати, докази та прогрес перевірки буде видалено.'))return;setBusy(true);google.script.run.withSuccessHandler(result=>{renderStatus(result.job);setBusy(false);showMessage('✅ '+result.message,'success')}).withFailureHandler(handleError).resetWaybackResults()}
    function refreshStatus(){google.script.run.withSuccessHandler(renderStatus).withFailureHandler(handleError).getWaybackJobStatus()}
    function startPolling(){if(refreshTimer)clearInterval(refreshTimer);refreshTimer=setInterval(refreshStatus,10000)}

    function renderStatus(job){
      job=job||{};const target=Number(job.targetDomains||0),processed=Number(job.processed||0),percentage=target?Math.min(100,Math.round(processed/target*100)):0;
      el('bar').style.width=percentage+'%';el('count').textContent=processed+' / '+target;el('clean').textContent=job.clean||0;el('warning').textContent=job.warning||0;el('critical').textContent=job.critical||0;el('errors').textContent=job.errors||0;el('message').textContent=String(job.message||'Готово до запуску').replace(/Бот без ШІ/g,'Бот працює');el('lastRow').textContent='Останній оброблений рядок: '+(job.lastProcessedRow||'—');
      const names={idle:'Очікування',running:'Працює у фоні',completed:'Завершено',stopped:'Зупинено',error:'Помилка'};el('state').textContent=names[job.state]||job.state||'Очікування';
      const running=job.state==='running';el('resumeButton').disabled=!['stopped','error'].includes(job.state);el('startButton').disabled=running;el('clearButton').disabled=running;
    }
    let policySaving=false;
    function policyChanged(){el('policyMessage').textContent='Є незбережені зміни. Натисни «Зберегти статуси».';}
    function savePolicy(){
      if(policySaving)return;
      const policy=readPolicy();policySaving=true;
      el('savePolicyButton').disabled=true;
      document.querySelectorAll('[data-topic]').forEach(x=>x.disabled=true);
      el('policyMessage').textContent='Збереження статусів…';
      const finish=()=>{policySaving=false;el('savePolicyButton').disabled=false;document.querySelectorAll('[data-topic]').forEach(x=>x.disabled=x.dataset.topic==='Казино/ставки');};
      google.script.run.withSuccessHandler(saved=>{
        document.querySelectorAll('[data-topic]').forEach(x=>{if(saved[x.dataset.topic])x.value=saved[x.dataset.topic];});
        finish();el('policyMessage').textContent='✅ Статуси збережено. Вони залишаться після закриття панелі. Можна змінити та зберегти знову.';
      }).withFailureHandler(error=>{finish();el('policyMessage').textContent='❌ Не збережено: '+(error&&error.message?error.message:String(error));}).saveWaybackTopicPolicy(policy);
    }
    function readPolicy(){const p={};document.querySelectorAll('[data-topic]').forEach(x=>p[x.dataset.topic]=x.value);return p;}
    function resumeAnalysis(){setBusy(true);el('resumeButton').disabled=true;google.script.run.withSuccessHandler(j=>{renderStatus(j);setBusy(false)}).withFailureHandler(handleError).resumeWaybackAnalysis();}
    google.script.run.withSuccessHandler(p=>{Object.keys(p).forEach(k=>{const label=document.createElement('label');label.textContent=k;const select=document.createElement('select');select.dataset.topic=k;[['block','Заборонено'],['review','Ручна перевірка'],['allow','Дозволено']].forEach(a=>{const o=document.createElement('option');o.value=a[0];o.textContent=a[1];select.appendChild(o)});select.value=p[k];select.onchange=policyChanged;select.disabled=k==='Казино/ставки';el('topicRules').append(label,select)});el('policyMessage').textContent='Завантажено поточні статуси. Зміни їх і натисни «Зберегти статуси».';initializePanel();}).withFailureHandler(handleError).getWaybackTopicPolicy();
  </script>
</body>
</html>