const btnScan = document.getElementById('btnScan');
const btnExport = document.getElementById('btnExport');
const btnActivate = document.getElementById('btnActivate');
const statusEl = document.getElementById('status');
const activationCodeInput = document.getElementById('activationCode');

let collectedNotes = [];
const FREE_LIMIT = 50;
let userState = { exportedCount: 0, activated: false, usedCodes: [] };

// === License logic ===
const LICENSE_SECRET = 'flomo_export_v1_2026_x7K9pQmZ'; // 修改这个值会让所有已生成的激活码失效

async function validateCode(code) {
  if (!code) return false;
  code = code.trim().toUpperCase();
  if (!/^FLOMO-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/.test(code)) return false;

  const parts = code.split('-');
  const serial = parts[1] + parts[2];
  const checksum = parts[3];

  const data = new TextEncoder().encode(LICENSE_SECRET + serial);
  const hashBuf = await crypto.subtle.digest('SHA-256', data);
  const hashArr = Array.from(new Uint8Array(hashBuf));
  const hashHex = hashArr.map(b => b.toString(16).padStart(2, '0')).join('').toUpperCase();
  // 把0/O/1/I 替换以避免歧义字符
  const hashClean = hashHex.replace(/[OIL]/g, c => ({O:'0', I:'1', L:'1'}[c]));
  const expected = hashClean.substring(0, 4);
  return checksum === expected;
}

async function loadState() {
  return new Promise(resolve => {
    chrome.storage.sync.get(['exportedCount', 'activated', 'usedCodes'], data => {
      userState.exportedCount = data.exportedCount || 0;
      userState.activated = !!data.activated;
      userState.usedCodes = data.usedCodes || [];
      resolve();
    });
  });
}

async function saveState() {
  return new Promise(resolve => {
    chrome.storage.sync.set({
      exportedCount: userState.exportedCount,
      activated: userState.activated,
      usedCodes: userState.usedCodes
    }, resolve);
  });
}

function refreshLicenseUI() {
  const freeBox = document.getElementById('licenseFree');
  const proBox = document.getElementById('licensePro');
  const actBox = document.getElementById('activationBox');
  const countEl = document.getElementById('exportedCount');
  if (userState.activated) {
    freeBox.style.display = 'none';
    proBox.style.display = 'block';
    actBox.style.display = 'none';
  } else {
    freeBox.style.display = 'block';
    proBox.style.display = 'none';
    actBox.style.display = 'flex';
    countEl.textContent = userState.exportedCount;
  }
}

btnActivate.addEventListener('click', async () => {
  const code = activationCodeInput.value.trim().toUpperCase();
  if (!code) {
    setStatus('请输入激活码', 'err');
    return;
  }
  if (userState.usedCodes.includes(code)) {
    setStatus('该激活码已被使用，请勿重复使用', 'err');
    return;
  }
  const ok = await validateCode(code);
  if (!ok) {
    setStatus('激活码无效', 'err');
    return;
  }
  userState.activated = true;
  userState.usedCodes.push(code);
  await saveState();
  refreshLicenseUI();
  activationCodeInput.value = '';
  setStatus('✓ 激活成功！现在可无限导出', 'ok');
});

function setStatus(text, cls = '') {
  statusEl.textContent = text;
  statusEl.className = cls;
}

// 获取激活码弹窗
const btnBuy = document.getElementById('btnBuy');
const buyModal = document.getElementById('buyModal');
const modalClose = document.getElementById('modalClose');
const faqContent = document.getElementById('faqContent');

async function loadFaq() {
  try {
    const url = chrome.runtime.getURL('常见问题.txt');
    const r = await fetch(url);
    const text = await r.text();
    // 把第一行作标题，问答交替加粗
    const lines = text.split('\n').map(l => l.trim());
    let html = '';
    let isQuestion = true;
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i];
      if (!line) { html += '\n'; isQuestion = true; continue; }
      if (i === 0) {
        html += `<strong>${line}</strong>\n`;
        continue;
      }
      if (isQuestion) {
        html += `<strong>${line}</strong>\n`;
        isQuestion = false;
      } else {
        html += `${line}\n`;
      }
    }
    faqContent.innerHTML = html;
  } catch (e) {
    faqContent.textContent = '常见问题加载失败: ' + e.message;
  }
}

btnBuy.addEventListener('click', () => {
  buyModal.classList.add('show');
  if (faqContent.textContent === '加载中...') loadFaq();
});

modalClose.addEventListener('click', () => {
  buyModal.classList.remove('show');
});

buyModal.addEventListener('click', (e) => {
  if (e.target === buyModal) buyModal.classList.remove('show');
});

// 初始化
(async () => {
  await loadState();
  refreshLicenseUI();
})();

async function getTab() {
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  return tab;
}

function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }

async function doScan(tabId) {
  const r = await chrome.scripting.executeScript({
    target: { tabId },
    func: scanPage
  });
  return r[0].result;
}

async function scrollOnce(tabId) {
  await chrome.scripting.executeScript({
    target: { tabId },
    func: () => {
      // 找最大的可滚动容器
      const all = document.querySelectorAll('div, main, section');
      let best = null, bestDiff = 0;
      for (const el of all) {
        const s = getComputedStyle(el);
        if ((s.overflowY === 'auto' || s.overflowY === 'scroll')) {
          const diff = el.scrollHeight - el.clientHeight;
          if (diff > bestDiff) { bestDiff = diff; best = el; }
        }
      }
      if (best) best.scrollTop = best.scrollHeight;
      try { window.scrollTo(0, document.body.scrollHeight); } catch (e) {}
      try { document.documentElement.scrollTop = document.documentElement.scrollHeight; } catch (e) {}
    }
  });
}

function findOldestDate(candidates) {
  let oldest = null;
  for (const c of candidates) {
    const d = parseNoteDate(c.date);
    if (d && (!oldest || d < oldest)) oldest = d;
  }
  return oldest;
}

btnScan.addEventListener('click', async () => {
  const tab = await getTab();
  if (!tab.url || !tab.url.includes('flomoapp.com')) {
    setStatus('请先打开 flomo 网页版', 'err');
    return;
  }

  const dateFrom = document.getElementById('dateFrom').value;
  btnScan.disabled = true;

  try {
    let data;

    if (dateFrom) {
      // 自动滚动加载，直到加载到 dateFrom 之前的笔记或滚到底
      setStatus(`自动加载至 ${dateFrom}...`);
      let lastCount = 0;
      let stableCount = 0;
      const maxIter = 150;

      for (let i = 0; i < maxIter; i++) {
        await scrollOnce(tab.id);
        await sleep(900);
        data = await doScan(tab.id);
        const count = data.candidates.length;
        const oldest = findOldestDate(data.candidates);

        setStatus(`已加载 ${count} 条 | 最旧: ${oldest || '未知'} | 目标: ${dateFrom}`);

        // 已到达目标日期之前
        if (oldest && oldest <= dateFrom) {
          setStatus(`已加载到目标日期（${oldest}）`);
          break;
        }

        // 数量不再增长 → 到底了
        if (count === lastCount) {
          stableCount++;
          if (stableCount >= 6) {
            setStatus(`已滚动到底，共 ${count} 条`);
            break;
          }
        } else {
          stableCount = 0;
          lastCount = count;
        }
      }
    } else {
      setStatus('扫描中...');
      data = await doScan(tab.id);
    }

    let report = '';
    report += `URL: ${data.url}\n`;
    report += `候选笔记数: ${data.candidates.length}\n\n`;

    if (data.candidates.length > 0) {
      data.candidates.slice(0, 5).forEach((c, i) => {
        report += `[${i+1}] ${c.date}\n`;
        report += `    ${c.bodyPreview}\n\n`;
      });
      collectedNotes = data.candidates;
      btnExport.disabled = false;
      const oldest = findOldestDate(collectedNotes);
      report += `\n✓ 共 ${collectedNotes.length} 条 (最旧: ${oldest || '未知'})\n点"导出"下载`;
    } else {
      report += `未识别到笔记\nheaders 检测数: ${data.headerCount}\n`;
    }

    setStatus(report, data.candidates.length > 0 ? 'ok' : 'err');
  } catch (e) {
    setStatus('出错: ' + e.message, 'err');
  }
  btnScan.disabled = false;
});

function parseNoteDate(dateStr) {
  // 从笔记日期文本（如 "置顶・2022-08-09 08:52" 或 "2026-04-06 05:49"）抽出 YYYY-MM-DD
  const m = dateStr.match(/(\d{4})[-/年](\d{1,2})[-/月](\d{1,2})/);
  if (!m) return null;
  const y = m[1];
  const mo = m[2].padStart(2, '0');
  const d = m[3].padStart(2, '0');
  return `${y}-${mo}-${d}`;
}

btnExport.addEventListener('click', async () => {
  if (collectedNotes.length === 0) {
    setStatus('没有可导出的内容', 'err');
    return;
  }

  // 日期范围过滤
  const dateFrom = document.getElementById('dateFrom').value; // YYYY-MM-DD or ''
  const dateTo = document.getElementById('dateTo').value;

  let toExport = collectedNotes;
  if (dateFrom || dateTo) {
    toExport = collectedNotes.filter(c => {
      const noteDate = parseNoteDate(c.date);
      if (!noteDate) return false; // 无日期的不在范围内导出
      if (dateFrom && noteDate < dateFrom) return false;
      if (dateTo && noteDate > dateTo) return false;
      return true;
    });
  }

  if (toExport.length === 0) {
    setStatus('日期范围内没有匹配的笔记', 'err');
    return;
  }

  // 免费版限额检查
  if (!userState.activated) {
    const remaining = FREE_LIMIT - userState.exportedCount;
    if (remaining <= 0) {
      setStatus(`已达到免费版上限 ${FREE_LIMIT} 条\n请输入激活码后继续使用`, 'err');
      return;
    }
    if (toExport.length > remaining) {
      setStatus(`免费版剩余 ${remaining} 条，将只导出最新 ${remaining} 条\n输入激活码后可无限制导出`, 'err');
      toExport = toExport.slice(0, remaining);
    }
  }

  const filterInfo = (dateFrom || dateTo)
    ? `（筛选: ${dateFrom || '不限'} ~ ${dateTo || '不限'}）`
    : '';
  setStatus(`正在打包 ${toExport.length} 条笔记 ${filterInfo}...`);

  const usedNames = new Set();
  const files = [];

  for (let i = 0; i < toExport.length; i++) {
    const c = toExport[i];
    let baseName = (c.date || `note_${i+1}`)
      .replace(/[\\/:*?"<>|]/g, '_')
      .replace(/\s+/g, '_')
      .replace(/・/g, '_')
      .trim() || `note_${i+1}`;

    let filename = `${baseName}.md`;
    let n = 1;
    while (usedNames.has(filename)) {
      n++;
      filename = `${baseName}_${n}.md`;
    }
    usedNames.add(filename);

    const md = `# ${c.date || '笔记 ' + (i+1)}\n\n${c.body}\n`;
    files.push({
      name: filename,
      data: new TextEncoder().encode(md)
    });
  }

  // Build ZIP
  const zipBytes = buildZip(files);
  const blob = new Blob([zipBytes], { type: 'application/zip' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  const d = new Date();
  const ds = `${d.getFullYear()}${String(d.getMonth()+1).padStart(2,'0')}${String(d.getDate()).padStart(2,'0')}`;
  a.download = `flomo_${ds}.zip`;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);

  // 更新已导出数量
  if (!userState.activated) {
    userState.exportedCount += toExport.length;
    await saveState();
    refreshLicenseUI();
  }

  const remainTip = !userState.activated
    ? `\n免费版剩余 ${Math.max(0, FREE_LIMIT - userState.exportedCount)} 条`
    : '';
  setStatus(`✓ 已打包 ${toExport.length} 条笔记到 zip ${filterInfo}${remainTip}`, 'ok');
});

// === Minimal ZIP encoder (STORED, no compression) ===
const crc32Table = (() => {
  const t = new Uint32Array(256);
  for (let i = 0; i < 256; i++) {
    let c = i;
    for (let k = 0; k < 8; k++) {
      c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
    }
    t[i] = c >>> 0;
  }
  return t;
})();

function crc32(data) {
  let c = 0xFFFFFFFF;
  for (let i = 0; i < data.length; i++) {
    c = crc32Table[(c ^ data[i]) & 0xFF] ^ (c >>> 8);
  }
  return (c ^ 0xFFFFFFFF) >>> 0;
}

function buildZip(files) {
  const enc = new TextEncoder();
  const local = [];
  let offset = 0;

  for (const f of files) {
    const nameBytes = enc.encode(f.name);
    const data = f.data;
    const crc = crc32(data);

    const lfh = new Uint8Array(30 + nameBytes.length);
    const lv = new DataView(lfh.buffer);
    lv.setUint32(0, 0x04034b50, true);
    lv.setUint16(4, 20, true);
    lv.setUint16(6, 0x0800, true); // UTF-8 flag
    lv.setUint16(8, 0, true);
    lv.setUint16(10, 0, true);
    lv.setUint16(12, 0x21, true);
    lv.setUint32(14, crc, true);
    lv.setUint32(18, data.length, true);
    lv.setUint32(22, data.length, true);
    lv.setUint16(26, nameBytes.length, true);
    lv.setUint16(28, 0, true);
    lfh.set(nameBytes, 30);

    local.push({ header: lfh, data: data, offset: offset, crc: crc, name: nameBytes });
    offset += lfh.length + data.length;
  }

  const centralStart = offset;
  const centralParts = [];
  let centralSize = 0;

  for (const f of local) {
    const cdh = new Uint8Array(46 + f.name.length);
    const cv = new DataView(cdh.buffer);
    cv.setUint32(0, 0x02014b50, true);
    cv.setUint16(4, 20, true);
    cv.setUint16(6, 20, true);
    cv.setUint16(8, 0x0800, true);
    cv.setUint16(10, 0, true);
    cv.setUint16(12, 0, true);
    cv.setUint16(14, 0x21, true);
    cv.setUint32(16, f.crc, true);
    cv.setUint32(20, f.data.length, true);
    cv.setUint32(24, f.data.length, true);
    cv.setUint16(28, f.name.length, true);
    cv.setUint16(30, 0, true);
    cv.setUint16(32, 0, true);
    cv.setUint16(34, 0, true);
    cv.setUint16(36, 0, true);
    cv.setUint32(38, 0, true);
    cv.setUint32(42, f.offset, true);
    cdh.set(f.name, 46);
    centralParts.push(cdh);
    centralSize += cdh.length;
  }

  const eocd = new Uint8Array(22);
  const ev = new DataView(eocd.buffer);
  ev.setUint32(0, 0x06054b50, true);
  ev.setUint16(4, 0, true);
  ev.setUint16(6, 0, true);
  ev.setUint16(8, files.length, true);
  ev.setUint16(10, files.length, true);
  ev.setUint32(12, centralSize, true);
  ev.setUint32(16, centralStart, true);
  ev.setUint16(20, 0, true);

  const total = offset + centralSize + 22;
  const out = new Uint8Array(total);
  let pos = 0;
  for (const f of local) {
    out.set(f.header, pos); pos += f.header.length;
    out.set(f.data, pos); pos += f.data.length;
  }
  for (const c of centralParts) {
    out.set(c, pos); pos += c.length;
  }
  out.set(eocd, pos);
  return out;
}

// === Injected into page ===
function scanPage() {
  // flomo 用 class="header" 包裹时间，直接找它最可靠
  const headers = Array.from(document.querySelectorAll('.header'));

  const candidates = [];
  const seen = new Set();

  for (const h of headers) {
    const headerText = (h.innerText || '').trim();
    if (!headerText) continue;
    // header 必须含数字或日期关键词
    if (!/\d|今天|昨天|前天|刚刚/.test(headerText)) continue;
    if (headerText.length > 50) continue;

    // 向上找笔记容器：parentElement 通常就是
    let container = h.parentElement;
    if (!container) continue;

    // 如果父元素文本太短（可能 header 上面还有一层wrapper），再向上一层
    let containerText = (container.innerText || '').trim();
    if (containerText.length <= headerText.length + 5 && container.parentElement) {
      container = container.parentElement;
      containerText = (container.innerText || '').trim();
    }

    if (seen.has(container)) continue;
    seen.add(container);

    // 正文 = 容器文本去掉 header 文本
    let body = containerText;
    const idx = body.indexOf(headerText);
    if (idx !== -1) {
      body = (body.substring(0, idx) + body.substring(idx + headerText.length)).trim();
    }

    if (!body) continue;

    candidates.push({
      date: headerText,
      body: body,
      bodyPreview: body.substring(0, 80).replace(/\s+/g, ' ')
    });
  }

  return {
    url: window.location.href,
    headerCount: headers.length,
    candidates: candidates
  };
}
