/**
 * 축제 크롤러 - 검색 페이지에서 게시글 URL 수집
 */

const FETCH_TIMEOUT = 15000;
const MAX_PAGES = 10; // 안전 상한

/**
 * 타임아웃이 적용된 fetch
 */
async function fetchWithTimeout(url, timeout = FETCH_TIMEOUT) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeout);
  try {
    const res = await fetch(url, {
      signal: controller.signal,
      headers: { 'User-Agent': 'Mozilla/5.0 (compatible; fromis9-bot)' },
    });
    clearTimeout(timeoutId);
    if (!res.ok) {
      throw new Error(`HTTP ${res.status}`);
    }
    return res;
  } catch (err) {
    clearTimeout(timeoutId);
    if (err.name === 'AbortError') {
      throw new Error('요청 타임아웃');
    }
    throw err;
  }
}

/**
 * HTML에서 게시글(/entry/) URL 추출
 * @param {string} html - 검색 페이지 HTML
 * @param {string} origin - 사이트 origin (예: https://memogipost.tistory.com)
 * @returns {string[]} 절대 URL 배열
 */
export function extractEntryUrls(html, origin) {
  const urls = new Set();
  // href="/entry/..." 또는 href="https://.../entry/..."
  const regex = /href="((?:https?:\/\/[^"]+)?\/entry\/[^"]+)"/g;
  let match;
  while ((match = regex.exec(html)) !== null) {
    let url = match[1];
    if (url.startsWith('/')) {
      url = origin + url;
    }
    // 쿼리스트링/해시 제거
    url = url.split('#')[0].split('?')[0];
    urls.add(url);
  }
  return [...urls];
}

/**
 * 검색 페이지를 페이지네이션하며 모든 게시글 URL 수집
 * @param {string} searchUrl - 검색 페이지 기본 URL
 * @param {object} log - 로거 (선택)
 * @returns {Promise<string[]>} 게시글 URL 배열 (중복 제거)
 */
export async function fetchSearchPostUrls(searchUrl, log = null) {
  // origin 추출
  const origin = new URL(searchUrl).origin;
  const allUrls = [];
  const seen = new Set();

  for (let page = 1; page <= MAX_PAGES; page++) {
    const pageUrl = searchUrl.includes('?')
      ? `${searchUrl}&page=${page}`
      : `${searchUrl}?page=${page}`;

    let html;
    try {
      const res = await fetchWithTimeout(pageUrl);
      html = await res.text();
    } catch (err) {
      log?.warn?.(`[festival] 페이지 ${page} 조회 실패: ${err.message}`);
      break;
    }

    const urls = extractEntryUrls(html, origin);
    const newUrls = urls.filter(u => !seen.has(u));

    if (newUrls.length === 0) {
      // 더 이상 새 게시글 없음 → 종료
      break;
    }

    for (const u of newUrls) {
      seen.add(u);
      allUrls.push(u);
    }
    log?.info?.(`[festival] 페이지 ${page}: ${newUrls.length}개 게시글`);

    // 페이지 간 간격
    await new Promise(r => setTimeout(r, 500));
  }

  return allUrls;
}
