#!/usr/bin/env python3
"""
金乡县-信息公开 爬虫 (Hanweb JPage)
站点: www.jinxiang.gov.cn
栏目: col32281 (信息公开 - 新材料产业园)
"""
import requests, re, sqlite3, time, sys
from bs4 import BeautifulSoup
import warnings
warnings.filterwarnings('ignore')
from datetime import datetime, timedelta
import os

SEARCH_DB = os.getenv("SEARCH_DB", "/root/search.db")
SITE_NAME = "金乡新材料产业园-信息公开"
DOMAIN = "www.jinxiang.gov.cn"
COLUMN_ID = "32281"
UNIT_ID = "98435"
WEB_ID = "96"

CUTOFF = (datetime.now() - timedelta(days=3*365)).strftime("%Y-%m-%d")
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}

JPROXY = f"http://{DOMAIN}/module/web/jpage/dataproxy.jsp"


def fetch_list_page(page):
    """通过JPage AJAX获取列表页"""
    start = (page - 1) * 15 + 1
    end = page * 15
    params = (
        f"startrecord={start}&endrecord={end}&perpage=15"
        f"&unitid={UNIT_ID}&webid={WEB_ID}"
        f"&path=http%3A%2F%2F{DOMAIN}"
        f"&webname=%E9%87%91%E4%B9%A1%E5%8E%BF%E4%BA%BA%E6%B0%91%E6%94%BF%E5%BA%9C"
        f"&col=1&columnid={COLUMN_ID}&sourceContentType=1&permissiontype=0"
    )
    url = f"{JPROXY}?{params}"

    for retry in range(3):
        try:
            r = requests.get(url, headers=HEADERS, timeout=30)
            if r.status_code == 200:
                r.encoding = "utf-8"
                records = re.findall(r'<record><!\[CDATA\[(.*?)\]\]></record>', r.text, re.DOTALL)

                items = []
                for rec in records:
                    m = re.search(r"href='([^']*)'[^>]*title='([^']*)'", rec)
                    if not m:
                        continue
                    href = m.group(1).strip()
                    title = m.group(2).strip()
                    dm = re.search(r'<span[^>]*>\[(\d{4}-\d{2}-\d{2})\]</span>', rec)
                    date = dm.group(1) if dm else ""

                    # Fix missing / in URL
                    if href.startswith('http://') and 'gov.cnart/' in href:
                        href = href.replace('gov.cnart/', 'gov.cn/art/', 1)
                    elif not href.startswith('http'):
                        href = f"http://{DOMAIN}{href}" if href.startswith('/') else f"http://{DOMAIN}/{href}"

                    items.append({"url": href, "title": title, "date": date})

                # Total pages from API response
                pm = re.search(r'<totalpage>(\d+)</totalpage>', r.text)
                total_pages = int(pm.group(1)) if pm else 10
                return items, total_pages
        except Exception as e:
            if retry < 2:
                time.sleep(2)
    return [], 0


def extract_content(html):
    """从 id=zoom > div.wenz 提取正文"""
    soup = BeautifulSoup(html, 'html.parser')
    zoom = soup.find('div', id='zoom')
    if zoom:
        for tag in zoom.find_all(['script', 'style']):
            tag.decompose()
        text = zoom.get_text(strip=True)
        if len(text) > 30:
            return str(zoom)
    # Fallback: article div
    art = soup.find('div', class_='article')
    if art:
        for tag in art.find_all(['script', 'style']):
            tag.decompose()
        text = art.get_text(strip=True)
        if len(text) > 30:
            return str(art)
    return ""


def extract_meta(html):
    soup = BeautifulSoup(html, 'html.parser')
    title = ""
    tm = soup.find('meta', attrs={"name": "ArticleTitle"})
    if tm and tm.get('content'):
        title = tm['content'].strip()
    if not title:
        tt = soup.find('title')
        if tt:
            title = tt.get_text(strip=True)

    date = ""
    # Note: lowercase 'pubdate' in this CMS
    for attr in ['pubdate', 'PubDate']:
        pm = soup.find('meta', attrs={"name": attr})
        if pm and pm.get('content'):
            d = pm['content'].strip()
            cm = re.match(r'(\d{4})-(\d{1,2})-(\d{1,2})', d)
            if cm:
                date = f"{cm.group(1)}-{cm.group(2).zfill(2)}-{cm.group(3).zfill(2)}"
                break
    if not date:
        dm = re.search(r'(\d{4}-\d{2}-\d{2})', html)
        if dm:
            date = dm.group(1)
    return title, date


def insert_article(url, title, date, content):
    db = sqlite3.connect(SEARCH_DB, timeout=60)
    db.execute("PRAGMA journal_mode=WAL")
    try:
        db.execute(
            "INSERT OR IGNORE INTO gov_raw(site_name,source_url,page_url,title,publish_date,content,summary,status,category) VALUES(?,?,?,?,?,?,?,?,?)",
            (SITE_NAME, url, url, title, date, content, title[:200], "active", "信息公开"))
        affected = db.total_changes
        db.commit()
        if affected:
            db.execute(
                "INSERT INTO gov_search(rowid,title,site_name,summary) SELECT r.id,r.title,r.site_name,r.summary FROM gov_raw r WHERE r.page_url=? AND r.id NOT IN (SELECT rowid FROM gov_search)",
                (url,))
            db.commit()
        db.close()
        return affected
    except Exception as e:
        db.close()
        print(f"  DB error: {e}")
        return 0


def run(max_pages=15):
    print(f"\n{'='*50}")
    print(f"🚀 {SITE_NAME}")
    print(f"{'='*50}")

    items, total_pages = fetch_list_page(1)
    if not items:
        print("❌ 列表页无数据")
        return

    total_pages = min(max_pages, total_pages)
    print(f"  共{total_pages}页, 约145条")

    all_items = list(items)
    for pg in range(2, total_pages + 1):
        its, _ = fetch_list_page(pg)
        if not its:
            break
        all_items.extend(its)
        dates = [it["date"] for it in its if it["date"]]
        if dates:
            print(f"  第{pg}页: {len(its)} 条 ({min(dates)} ~ {max(dates)})")
        else:
            print(f"  第{pg}页: {len(its)} 条")
        time.sleep(0.2)

    print(f"\n📊 共 {len(all_items)} 条")
    new = skip = no_body = err = 0
    for i, item in enumerate(all_items, 1):
        if item["date"] and item["date"] < CUTOFF:
            skip += 1
            continue

        for retry in range(3):
            try:
                r = requests.get(item["url"], headers=HEADERS, timeout=30)
                if r.status_code == 200:
                    r.encoding = "utf-8"
                    html = r.text
                    break
            except:
                if retry < 2:
                    time.sleep(2)
                html = None

        if not html:
            err += 1
            continue

        pt, pd = extract_meta(html)
        real_title = pt if pt else item["title"]
        real_date = pd if pd else item["date"]

        if real_date and real_date < CUTOFF:
            skip += 1
            continue

        content = extract_content(html)
        text_len = len(re.sub(r'<[^>]+>', '', content).strip()) if content else 0
        if text_len < 10:
            no_body += 1
            continue

        if insert_article(item["url"], real_title, real_date, content):
            new += 1
        else:
            skip += 1

        if i % 5 == 0:
            print(f"  ...{i}/{len(all_items)}")
        time.sleep(0.2)

    # FTS sync
    print(f"\n📊 FTS同步...")
    db = sqlite3.connect(SEARCH_DB, timeout=60)
    # QC20260926 去掉手写 gov_search 整站删除(抢锁源; FTS 由 gov_raw 触发器维护) 
    # db.execute("DELETE FROM gov_search WHERE site_name=?", (SITE_NAME,))
    db.execute("INSERT INTO gov_search(rowid,title,site_name,summary) SELECT rowid,title,site_name,summary FROM gov_raw WHERE site_name=?", (SITE_NAME,))
    db.commit()
    c = db.execute("SELECT COUNT(*) FROM gov_search WHERE site_name=?", (SITE_NAME,))
    cnt = c.fetchone()[0]
    db.close()
    print(f"  FTS: {cnt} 条")
    print(f"\n✅ {SITE_NAME}: 新增{new}, 跳过{skip}, 空正文{no_body}, 错误{err}, FTS共{cnt}条")


if __name__ == "__main__":
    mp = int(sys.argv[1]) if len(sys.argv) > 1 else 15
    run(mp)
