# -*- coding: utf-8 -*-
"""공공기관 N 이미지 — 게시판 전용 재판정(상세글 렌더 + 크기필터).

매뉴얼: 게시판 N 이미지 = 상세글 표본의 본문 실사진(첨부PDF/뷰어 제외).
대상: plan_{기관}.json 에서 L==게시판 & 원본N('이미지' 포함) 행.
각 게시판: 목록에서 상세URL 추출→상위 4개 렌더→본문 콘텐츠이미지(≥170×110, 노이즈제외) 있으면 이미지.
결과를 엑셀 N에 반영(게시판만). 사용: python _공공기관_nboard.py [기관명 ...]
"""
import sys, os, re, json, time, warnings, importlib.util
import requests, openpyxl
from urllib.parse import urljoin
from bs4 import BeautifulSoup
warnings.filterwarnings('ignore')

OUTDIR = r'D:\01.프로젝트\DB수집\공공기관'
TEMP = r'D:\01.프로젝트\DB수집\_temp'
UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
spec = importlib.util.spec_from_file_location('p234', r'D:\01.프로젝트\DB수집\_스크립트\_공공기관_phase234.py')
P = importlib.util.module_from_spec(spec); spec.loader.exec_module(P)
NOISE = re.compile(r'(ico[_\-/]|/icon|logo|btn|bul[_\-]|bg[_\-]|banner|sns|blank|spacer|loading|arrow|/dot|line[_\.]|top_|foot|header|common|_icon|symbol|copyright|qr_|no_img|noimage|share|facebook|insta|twitter|naver|kakao|/skin/|/template/|synap|pdf|viewer|/editor/icon)', re.I)

JS_IMGS = """() => { const o=[]; for(const i of document.querySelectorAll('img')){const r=i.getBoundingClientRect(); o.push({src:i.currentSrc||i.src||'',nw:i.naturalWidth,nh:i.naturalHeight,rw:Math.round(r.width),rh:Math.round(r.height)});} return o; }"""


def has_content_img(items):
    for it in items:
        s = it.get('src', '')
        if not s or NOISE.search(s):
            continue
        if it.get('nw', 0) >= 170 and it.get('nh', 0) >= 110 and it.get('rw', 0) >= 100 and it.get('rh', 0) >= 80:
            return True
    return False


def add_image(N):
    parts = [p for p in (N or '').split(',') if p]
    if '없음' in parts:
        parts = [p for p in parts if p != '없음']
    if '어문' not in parts:
        parts = ['어문'] + parts
    if '이미지' not in parts:
        # 어문 다음에 이미지
        out = []
        for p in parts:
            out.append(p)
            if p == '어문':
                out.append('이미지')
        parts = out
    return ','.join(parts)


def rm_image(N):
    parts = [p for p in (N or '').split(',') if p and p != '이미지']
    return ','.join(parts) if parts else '없음'


def run(name, pg):
    pf = os.path.join(TEMP, f'nshot_{name}', f'plan_{name}.json')
    if not os.path.exists(pf):
        print(f'[{name}] plan없음 스킵'); return
    plan = json.load(open(pf, encoding='utf-8'))
    boards = [it for it in plan if it.get('L') == '게시판' and '이미지' in (it.get('N') or '')]
    if not boards:
        print(f'[{name}] 재판정 게시판 0'); return
    xlsx = os.path.join(OUTDIR, f'{name}.xlsx')
    wb = openpyxl.load_workbook(xlsx)
    ws = wb.active
    sess = P.make_session()
    img_cnt = txt_cnt = 0
    montshots = []
    for it in boards:
        r, url = it['row'], it['url']
        try:
            soup, _ = P.fetch(sess, url)
            if not soup:
                continue
            body = P.get_body(soup, P.BODY_SEL)
            details = P.extract_detail_urls(body, url, limit=4)
            found = False
            for du in details:
                try:
                    pg.goto(du, timeout=20000, wait_until='domcontentloaded'); pg.wait_for_timeout(1500)
                    if has_content_img(pg.evaluate(JS_IMGS)):
                        found = True
                        sp = os.path.join(TEMP, f'nshot_{name}', f'bd_r{r}.png')
                        try:
                            pg.screenshot(path=sp); montshots.append((r, sp))
                        except Exception:
                            pass
                        break
                except Exception:
                    continue
            cur = ws.cell(r, 14).value or ''
            if found:
                ws.cell(r, 14).value = add_image(cur); img_cnt += 1
            else:
                ws.cell(r, 14).value = rm_image(cur); txt_cnt += 1
        except Exception:
            continue
    wb.save(xlsx)
    print(f'[{name}] 게시판재판정 {len(boards)}개 → 이미지 {img_cnt}·어문 {txt_cnt}')
    return montshots


def main():
    from playwright.sync_api import sync_playwright
    probe = {r['name']: r for r in json.load(open(r'D:\01.프로젝트\DB수집\_스크립트\_공공기관_probe.json', encoding='utf-8'))}
    order = sorted(probe.values(), key=lambda x: -int(x['num']))
    only = sys.argv[1:]
    if only:
        order = [p for p in order if p['name'] in only or str(p['num']) in only]
    with sync_playwright() as pw:
        b = pw.chromium.launch()
        pg = b.new_page(user_agent=UA, viewport={'width': 1280, 'height': 1600})
        for p in order:
            try:
                run(p['name'], pg)
            except Exception as e:
                print(f"[{p['name']}] 실패: {e}")
        b.close()
    print('=== 게시판 N 재판정 완료 ===')


if __name__ == '__main__':
    main()
