"""사이트 본문 탭(서브내비) 탐지 스캐너.

각 사이트 페이지를 받아 본문 탭 UL을 찾아, 탭이 2개 이상인 페이지를 보고한다.
공주시: ul.tab-ul. 다른 사이트도 흔한 탭 클래스 패턴을 함께 탐지.

사용법: python -X utf8 _tab_scan.py <엑셀경로> <도메인키워드>
예:    python -X utf8 _tab_scan.py 충청남도/2.공주시/충청남도_공주시.xlsx gongju.go.kr
"""
import re
import sys
import warnings
from concurrent.futures import ThreadPoolExecutor, as_completed
from urllib.parse import urljoin, urlparse

import openpyxl
import requests
from bs4 import BeautifulSoup

warnings.filterwarnings('ignore')

UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
H = {'User-Agent': UA}

# 흔한 본문 탭(서브내비) 컨테이너 클래스 패턴 (소문자 비교)
TAB_CLASS_PATS = [
    'tab-ul',      # 공주시
    'tab_ul',
    'tabmenu', 'tab-menu', 'tab_menu',
    'tablist', 'tab-list', 'tab_list',
    'subtab', 'sub-tab', 'sub_tab',
    'tab_wrap', 'tab-wrap',
]


def find_tab_uls(soup):
    """본문 탭으로 보이는 ul들을 반환. (ul, [(text,href),...]) 리스트."""
    results = []
    seen = set()
    for ul in soup.find_all('ul'):
        cls = ' '.join(ul.get('class') or []).lower()
        if not cls:
            # 부모 div의 클래스도 확인 (ul 자체엔 클래스 없고 div.tab > ul 구조)
            parent = ul.find_parent(['div'])
            pcls = ' '.join(parent.get('class') or []).lower() if parent else ''
            if not any(p in pcls for p in TAB_CLASS_PATS):
                continue
        elif not any(p in cls for p in TAB_CLASS_PATS):
            continue
        links = []
        for a in ul.find_all('a'):
            t = a.get_text(strip=True).replace('\xa0', '').strip()
            h = (a.get('href') or '').strip()
            if t:
                links.append((t, h))
        if len(links) >= 2:
            key = tuple(t for t, _ in links)
            if key not in seen:
                seen.add(key)
                results.append((cls, links))
    return results


def scan_one(r, url):
    try:
        resp = requests.get(url, headers=H, timeout=15, verify=False)
        resp.encoding = resp.apparent_encoding
        soup = BeautifulSoup(resp.text, 'html.parser')
        tabs = find_tab_uls(soup)
        return r, url, tabs, None
    except Exception as e:
        return r, url, [], str(e)[:60]


def main():
    xlsx = sys.argv[1]
    domain = sys.argv[2]
    wb = openpyxl.load_workbook(xlsx)
    ws = wb.active
    targets = []
    for r in range(3, ws.max_row + 1):
        u = ws.cell(r, 11).value
        if isinstance(u, str) and domain in u:
            targets.append((r, u))
    print(f'스캔 대상: {len(targets)}개 ({domain})')

    found = []
    errs = []
    with ThreadPoolExecutor(max_workers=8) as ex:
        futs = [ex.submit(scan_one, r, u) for r, u in targets]
        for fut in as_completed(futs):
            r, url, tabs, err = fut.result()
            if err:
                errs.append((r, url, err))
            elif tabs:
                found.append((r, url, tabs))

    found.sort()
    print(f'\n=== 탭 발견: {len(found)}개 페이지 ===')
    for r, url, tabs in found:
        e = ws.cell(r, 5).value or ''
        f = ws.cell(r, 6).value or ''
        g = ws.cell(r, 7).value or ''
        print(f'[행{r}] E={e} F={f} G={g}')
        print(f'      {url}')
        for cls, links in tabs:
            print(f'      <ul class={cls}> 탭 {len(links)}개:')
            for t, h in links:
                print(f'         - {t}  ->  {h}')
    if errs:
        print(f'\n=== 에러 {len(errs)}개 ===')
        for r, url, err in errs[:20]:
            print(f'[행{r}] {url} : {err}')


if __name__ == '__main__':
    main()
