# -*- coding: utf-8 -*-
"""중분류/소분류 '랜딩행' 제거 — 매뉴얼 1-5 확장(③ K동일 조건 제거).

_dedup_all.py 는 부모행 URL == 첫 자식 URL 일 때만 부모행을 삭제한다(③).
eGov '누리집지도'(고창·임실·정읍·진안 등)는 중분류 랜딩(예 …002000000 '민원안내')과
첫 소분류(…002007000)의 URL이 달라 ③에 안 걸리고 랜딩행이 남아 있다.
사용자 요청(2026-05-31): ③조건을 빼고, 자식을 거느린 부모 랜딩행을 전부 삭제.
  · 부모행의 가장 깊은 카테고리 컬럼 lc, lc+1은 빈칸(부모는 그 깊이의 잎이 아님)
  · 직후 자식행이 D~lc 값 동일 & lc+1 채워짐  → 부모행 삭제(자식이 병합으로 라벨 승계)
URL 무관. 카테고리 텍스트(D/E/F)는 재병합으로 보존.

평탄화/재병합/순번/하이퍼링크는 _dedup_all 재사용. 전 컬럼(B~AA, L~Q) 보존.

사용:
  python -X utf8 _collapse_landing.py dry  <기관명...|경로>
  python -X utf8 _collapse_landing.py run  <기관명...|경로>
  --maxlc N : lc<=N 깊이까지만 삭제(기본 9=I, 즉 D~I 랜딩 모두). E만 원하면 --maxlc 5.
"""
import os, sys, shutil, importlib.util, warnings
import openpyxl
warnings.filterwarnings('ignore')

spec = importlib.util.spec_from_file_location('dd', __file__.replace('_collapse_landing.py', '_dedup_all.py'))
dd = importlib.util.module_from_spec(spec); spec.loader.exec_module(dd)

CAT_COLS = dd.CAT_COLS  # D E F G H I J = 4..10
EXCLUDE = {'계룡시'}     # 검수완료


def is_safe_shell(v):
    """순수 메뉴 셸인가: L=페이지(또는 빈칸) & M<=1 & 공공누리 미부착."""
    L = v.get(12); M = v.get(13); O = v.get(15)
    if isinstance(O, str) and '유형' in O:
        return False
    if L not in (None, '', '페이지'):
        return False
    if isinstance(M, (int, float)) and M and M > 1:
        return False
    return True


def collapse(rows, maxlc=9, safe=False):
    """랜딩행 제거. safe=True면 순수 셸(데이터 무보유)만. 반환 (남은행, 제거목록)."""
    out, removed = [], []
    i = 0
    while i < len(rows):
        v = rows[i]['vals']
        if i + 1 < len(rows):
            nv = rows[i + 1]['vals']
            lc = dd.leaf_depth(v)              # 부모의 가장 깊은 카테고리 컬럼
            if 4 <= lc <= maxlc:
                same_upper = all((v.get(c) or '') == (nv.get(c) or '')
                                 for c in CAT_COLS if c <= lc)
                child_next = nv.get(lc + 1) not in (None, '')
                parent_is_landing = v.get(lc + 1) in (None, '')
                if safe and not is_safe_shell(v):
                    same_upper = False  # 데이터 보유 랜딩은 보존
                if same_upper and child_next and parent_is_landing:
                    removed.append({'src': rows[i]['src'], 'lc': lc,
                                    'label': v.get(lc), 'child': nv.get(lc + 1),
                                    'url': v.get(11), 'curl': nv.get(11)})
                    i += 1
                    continue
        out.append(rows[i]); i += 1
    return out, removed


LV = {4: 'D', 5: 'E', 6: 'F', 7: 'G', 8: 'H', 9: 'I', 10: 'J'}


def resolve(args):
    paths = []
    for a in args:
        if a.lower().endswith('.xlsx') or os.path.sep in a:
            paths.append((os.path.splitext(os.path.basename(a))[0], a))
    names = [a for a in args if not (a.lower().endswith('.xlsx') or os.path.sep in a)]
    for prov, idx, name in dd.SITES:
        if names and name in names:
            paths.append((name, dd.xpath(prov, idx, name)))
    return paths


def main():
    mode = sys.argv[1] if len(sys.argv) > 1 else 'dry'
    rest = [a for a in sys.argv[2:] if not a.startswith('--')]
    maxlc = 9
    if '--maxlc' in sys.argv:
        maxlc = int(sys.argv[sys.argv.index('--maxlc') + 1])
    safe = '--safe' in sys.argv
    targets = resolve(rest)
    if not targets:
        print('대상 없음.'); return
    grand = 0
    for name, xp in targets:
        if name in EXCLUDE:
            print(f'{name}: 검수완료 제외'); continue
        if not os.path.exists(xp):
            print(f'{name}: 엑셀 없음'); continue
        wb = openpyxl.load_workbook(xp); ws = wb.active
        rows = dd.load_flat(ws)
        out, removed = collapse(rows, maxlc, safe)
        grand += len(removed)
        bylv = {}
        for r in removed:
            bylv[r['lc']] = bylv.get(r['lc'], 0) + 1
        lvstr = ' '.join(f'{LV[k]}:{v}' for k, v in sorted(bylv.items()))
        print(f'\n=== {name} === {len(rows)}→{len(out)} (제거 {len(removed)})  [{lvstr}]')
        for r in removed[:6]:
            print(f"  [{LV[r['lc']]}] {r['label']}  ({r['url']})  → 자식 첫행 {r['child']} ({r['curl']})")
        if len(removed) > 6:
            print(f'  ... 외 {len(removed)-6}건')
        if mode == 'run' and removed:
            bak = xp.replace('.xlsx', '_backup_랜딩제거전.xlsx')
            shutil.copy(xp, bak)
            dd.write_back(ws, out)
            try:
                wb.save(xp)
            except PermissionError:
                wb.save(xp.replace('.xlsx', '_LP.xlsx')); print('   !! 잠김→_LP')
            else:
                print(f'   저장 완료. 백업: {os.path.basename(bak)}')
    print(f'\n총 제거 대상: {grand}행  ({mode}, maxlc={maxlc})')


if __name__ == '__main__':
    main()
