# -*- coding: utf-8 -*-
"""전력거래소: ①base GNB(ul#head_menu_all) 재추출 ②본문 ul#depth4_menu_ul 전수스캔
③member-set dedup·self탭 노드에 children 전개 → _gnb\2.json."""
import sys, io, os, json, re
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
from playwright.sync_api import sync_playwright

GNB = r"D:\01.프로젝트\DB수집\작업파일\공공기관2\_gnb\2.json"

def midkey(h):
    m = re.search(r'mid=([a-z0-9]+)', h or '')
    return m.group(1) if m else (h or '')

BASE_JS = """
() => {
  const root=document.querySelector('#head_menu_all')||document.querySelector('#head_menu');
  const rows=[];
  function walk(ul,depth){[...ul.children].filter(li=>li.tagName==='LI').forEach(li=>{
    let a=li.querySelector(':scope>a,:scope>div>a,:scope>span>a,:scope>button');
    let l=a?(a.textContent||'').trim().replace(/\\s+/g,' '):'';
    let h=a&&a.tagName==='A'?a.href:'';
    if(l)rows.push({depth,label:l,href:h});
    li.querySelectorAll(':scope>ul,:scope>div>ul').forEach(s=>walk(s,depth+1));});}
  walk(root,1); return rows;
}
"""
D4_JS = """
() => { const ul=document.querySelector('#depth4_menu_ul,ul#depth4_menu_ul'); if(!ul) return [];
  return [...ul.querySelectorAll(':scope>li>a')].map(a=>({label:(a.textContent||'').trim().replace(/\\s+/g,' '),href:a.href})); }
"""

with sync_playwright() as p:
    br=p.chromium.launch(headless=True)
    pg=br.new_context(ignore_https_errors=True,viewport={'width':1600,'height':1000}).new_page()
    # ① base GNB
    pg.goto('https://www.kpx.or.kr/main/',wait_until='domcontentloaded',timeout=30000); pg.wait_for_timeout(2500)
    base=pg.evaluate(BASE_JS)
    print('base GNB',len(base),'행')
    # 고유 kpx 페이지
    seen=set(); targets=[]
    for r in base:
        h=r.get('href') or ''
        if 'kpx.or.kr' in h and 'mid=' in h:
            k=midkey(h)
            if k not in seen: seen.add(k); targets.append((k,h))
    # ② depth4 스캔
    page_groups={}
    for i,(k,h) in enumerate(targets):
        try:
            pg.goto(h,wait_until='domcontentloaded',timeout=20000); pg.wait_for_timeout(600)
            d4=pg.evaluate(D4_JS)
        except Exception: d4=[]
        if len(d4)>=2: page_groups[k]=d4
        if (i+1)%30==0: print(f'  ...{i+1}/{len(targets)} (탭 {len(page_groups)})')
    br.close()

print(f'depth4 페이지 {len(page_groups)}개')
# ③ member-set dedup
uniq={}  # frozenset(member mids) -> items
for k,items in page_groups.items():
    key=frozenset(midkey(it['href']) for it in items)
    if key not in uniq: uniq[key]=items
print(f'고유 그룹 {len(uniq)}개')

# base 행 mid 집합
base_mids={midkey(r.get('href','')) for r in base}
# 각 고유그룹의 부모 결정: 멤버 중 base에 있는 노드(self탭) → 그 노드; 없으면 page_groups에서 base에 있는 페이지
def parent_mid_for(memberset, items):
    inb=[m for m in memberset if m in base_mids]
    if inb: return inb[0]  # self탭(멤버가 GNB노드)
    # fallback: 이 그룹을 보여준 페이지 중 base에 있는 것
    for k in page_groups:
        if frozenset(midkey(it['href']) for it in page_groups[k])==memberset and k in base_mids:
            return k
    return None

# 부모mid -> 전개할 items
expand={}
for key,items in uniq.items():
    pm=parent_mid_for(key,items)
    if pm and pm not in expand:
        expand[pm]=items

new=[]; done=set()
for r in base:
    new.append(r)
    k=midkey(r.get('href',''))
    if k in expand and k not in done:
        done.add(k)
        for it in expand[k]:
            new.append({'depth':r['depth']+1,'label':it['label'],'href':it['href']})

data={'num':2,'name':'한국전력거래소','base':'https://www.kpx.or.kr','gnb':new}
json.dump(data,open(GNB,'w',encoding='utf-8'),ensure_ascii=False,indent=1)
print(f'전개: {len(expand)}그룹 → 총 {len(new)}행 (base {len(base)})')
for pm,items in expand.items():
    print(f'  [{pm}] +{len(items)}: {", ".join(x["label"][:12] for x in items)}')
