#!/usr/bin/env python3
"""福泉市生态环境局 - 生态环境"""
import re, sys, os
import urllib.request, urllib.error
from bs4 import BeautifulSoup
import sqlite3

BASE_URL = "https://www.gzfuquan.gov.cn"
LIST_PATH = "/zwgk/zdlygk/sthj/"
SITE_NAME = "福泉市-生态环境"
SITE_DISPLAY = "福泉市人民政府"
GROUP_NAME = "环评平台"
DB = os.environ.get("SEARCH_DB", "/root/search.db")
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}

_MAX_PG = None
for i, a in enumerate(sys.argv):
    if a == "--pages" and i + 1 < len(sys.argv):
        _MAX_PG = int(sys.argv[i + 1])
        break

# ─── 正文取文本（2026-09-11）：行内节点直接拼接，只在块级边界 / <br> 处换行 ───
# ⚠️ 不要用 el.get_text("\n") 取正文 —— 它是「每个**文本节点**之间插 \n」，Word 粘贴的
#    公文把一行拆成 <span>提取码：</span>pwaj<span>。查阅…</span>，这些行内节点于是各自
#    成行（福泉 id=2095080103703914437 实例：`提取码：`/`pwaj`/`。查阅…` 各占一行）。
_BLOCK_TAGS = {'address', 'article', 'aside', 'blockquote', 'details', 'dialog', 'dd', 'div',
               'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2',
               'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'li', 'main', 'nav', 'ol',
               'p', 'pre', 'section', 'table', 'tbody', 'thead', 'tfoot', 'tr', 'td', 'th',
               'ul', 'center', 'caption'}


def body_text(el):
    """块级边界出换行、行内节点直接拼接、<br> 出换行（≈ 浏览器看到的换行结构）。"""
    if el is None:
        return ''
    import re as _re
    from bs4 import NavigableString
    out = []

    def walk(node):
        for ch in node.children:
            if isinstance(ch, NavigableString):
                out.append(str(ch))
            elif getattr(ch, 'name', None) == 'br':
                out.append('\n')
            elif getattr(ch, 'name', None) in _BLOCK_TAGS:
                out.append('\n')
                walk(ch)
                out.append('\n')
            else:
                walk(ch)
    walk(el)
    t = ''.join(out)
    t = _re.sub(r'[ \t\r\f\v]*\n[ \t\r\f\v]*', '\n', t)
    t = _re.sub(r'\n{3,}', '\n\n', t)
    return t.strip()


def html_table_to_html(table, base_url=""):
    """保留 HTML 表格结构，仅将相对链接/图片转绝对 URL"""
    import urllib.parse
    tbl = BeautifulSoup(str(table), 'html.parser')
    for a in tbl.find_all('a'):
        href = a.get('href', '')
        if href and not href.startswith(('http', 'javascript', '#')):
            a['href'] = urllib.parse.urljoin(base_url, href) if base_url else href
    for img in tbl.find_all('img'):
        src = img.get('src', '')
        if src and not src.startswith(('http', '//', 'data:')):
            img['src'] = urllib.parse.urljoin(base_url, src) if base_url else src
    return str(tbl)
def fetch(url):
    req = urllib.request.Request(url, headers=HEADERS)
    try:
        return urllib.request.urlopen(req, timeout=30).read().decode("utf-8", errors="replace")
    except Exception as e:
        print("[WARN] fetch failed: %s - %s" % (url, e), file=sys.stderr)
        return ""

def extract_items(html):
    soup = BeautifulSoup(html, "html.parser")
    items = []
    for li in soup.select("ul.NewsList > li"):
        a = li.find("a", href=True)
        if not a:
            continue
        href = a["href"].strip()
        title = a.get("title", "") or a.get_text(strip=True)
        date_span = li.find("span")
        date_text = date_span.get_text(strip=True) if date_span else ""
        if href.startswith("./"):
            href = BASE_URL + LIST_PATH.rstrip("/") + "/" + href[2:]
        elif not href.startswith("http"):
            if href.startswith("/"):
                href = BASE_URL + href
            else:
                href = BASE_URL + LIST_PATH.rstrip("/") + "/" + href
        items.append({"title": title.strip(), "url": href, "date": date_text})
    return items

def get_total_pages(html):
    m = re.search(r"createPageHTML\((\d+),\s*\d+,\s*\"index", html)
    if m:
        return int(m.group(1))
    return None

def parse_detail(html, url):
    soup = BeautifulSoup(html, "html.parser")
    title = ""
    meta_title = soup.find("meta", attrs={"name": "ArticleTitle"})
    if meta_title and meta_title.get("content"):
        title = meta_title["content"].strip()
    if not title:
        title_div = soup.select_one("div.ArticleTitle")
        if title_div:
            title = title_div.get_text(strip=True)
    if not title and soup.title:
        raw = soup.title.string.strip()
        raw = re.sub(r"^\S+\s+\S+\s+", "", raw)
        title = raw

    date_text = ""
    meta_date = soup.find("meta", attrs={"name": "PubDate"})
    if meta_date and meta_date.get("content"):
        m = re.search(r"(\d{4}-\d{2}-\d{2})", meta_date["content"])
        if m:
            date_text = m.group(1)

    zoom = soup.find("font", id="Zoom")
    if not zoom:
        return {"title": title, "date": date_text, "content": "", "images": [], "attachments": []}

    content_parts = []
    images = []
    attachments = []
    cells = []
    content_div = zoom.find("div", class_="trs_editor_view") or zoom

    for el in content_div.find_all(["p", "table", "img"], recursive=True):
        if el.name == "img":
            src = el.get("src", "").strip()
            alt = el.get("alt", "").strip()
            if src:
                if src.startswith("./"):
                    src = BASE_URL + LIST_PATH.rstrip("/") + "/" + src[2:]
                elif src.startswith("/"):
                    src = BASE_URL + src
                elif not src.startswith("http"):
                    src = BASE_URL + LIST_PATH.rstrip("/") + "/" + src
                images.append({"src": src, "alt": alt})
                content_parts.append("![%s](%s)" % (alt, src))
            continue

        if el.find_parent("table") and el.name != "table":
            continue

        if el.name == 'table':
            tbl_html = html_table_to_html(el, url)
            if tbl_html:
                cells.append(tbl_html)
        text = body_text(el)
        if text:
            for a in el.find_all("a", href=True):
                h = a["href"].lower()
                if h.endswith((".pdf", ".doc", ".docx", ".xls", ".xlsx", ".zip", ".rar")):
                    ah = a["href"]
                    if ah.startswith("./"):
                        ah = BASE_URL + LIST_PATH.rstrip("/") + "/" + ah[2:]
                    elif ah.startswith("/"):
                        ah = BASE_URL + ah
                    elif not ah.startswith("http"):
                        ah = BASE_URL + LIST_PATH.rstrip("/") + "/" + ah
                    attachments.append({"name": a.get_text(strip=True) or ah.split("/")[-1], "url": ah})
            content_parts.append(text)

    if cells:
        content_parts.extend(cells)
    content = "\n\n".join(p for p in content_parts if p.strip())
    return {"title": title, "date": date_text, "content": content, "images": images, "attachments": attachments}

def main():
    total_new = 0
    conn = sqlite3.connect(DB, timeout=60)
    c = conn.cursor()

    all_items = []
    page_num = 0
    while True:
        if page_num == 0:
            url = BASE_URL + LIST_PATH + "index.html"
        else:
            url = BASE_URL + LIST_PATH + "index_%d.html" % page_num

        html = fetch(url)
        if not html:
            print("[INFO] Page %d: empty response, stopping" % page_num, file=sys.stderr)
            break

        items = extract_items(html)
        if not items:
            print("[INFO] Page %d: no items found, stopping" % page_num, file=sys.stderr)
            break

        print("[INFO] Page %d: %d items" % (page_num, len(items)), file=sys.stderr)
        all_items.extend(items)

        if _MAX_PG and page_num + 1 >= _MAX_PG:
            break
        page_num += 1

    print("[INFO] Total collected: %d items" % len(all_items), file=sys.stderr)

    for idx, item in enumerate(all_items):
        if not item["url"] or "gov.cn" not in item["url"]:
            continue

        c.execute("SELECT id FROM gov_raw WHERE page_url=?", (item["url"],))
        if c.fetchone():
            continue

        html = fetch(item["url"])
        if not html:
            continue

        detail = parse_detail(html, item["url"])
        title = detail["title"] or item["title"]
        date_text = detail["date"] or item["date"]
        content = detail["content"]
        attachments_json = json.dumps(detail["attachments"], ensure_ascii=False) if detail.get("attachments") else "[]"

        if not content.strip():
            content = title
            print("[WARN] Empty content: %s" % title, file=sys.stderr)

        summary = content[:200].replace("\n", " ").strip()

        try:
            c.execute("INSERT OR IGNORE INTO gov_raw (page_url, title, site_name, group_name, publish_date, summary, content, attachments, date_rank) VALUES (?,?,?,?,?,?,?,?,?)",
                (item["url"], title, SITE_NAME, GROUP_NAME, date_text, summary, content, attachments_json, date_text))
            conn.commit()
            total_new += 1
            if total_new % 10 == 0:
                print("[INFO] Inserted %d/%d" % (total_new, len(all_items)), file=sys.stderr)
        except Exception as e:
            print("[WARN] DB insert failed: %s - %s" % (title[:30], e), file=sys.stderr)

    conn.close()
    print("[DONE] Fuquan: %d new items" % total_new)

if __name__ == "__main__":
    import json
    main()
