# -*- coding: utf-8 -*-
"""이번에 채택된 E500PRO 부재를 manifest.json 에 '추가만' 한다.
   기존 항목은 건드리지 않는다. 중복 판정은 '파일명'이 아니라 '도번'으로 한다.
   (같은 도번이 다른 파일명으로 이미 들어 있는 경우가 있었다 — E500PRO_부재시범.obj = 0018-001)
   note 에는 두께 근거를 도면 원문 그대로 남긴다. VLM 으로 읽은 값은 그렇게 표기한다."""
import json, os, re, shutil, sys, time

# 결과 파일(multi_result.json)은 pass6_multi.py 가 '작업 스크래치패드'에 쓴다.
# 예전에는 여기서 스크립트 폴더(dwg2obj)를 보고 있어서, 손으로 복사해 주지 않으면
# 파일을 못 찾았다. 경로 상수는 shape_common.SCR 하나만 쓰도록 맞춘다(같은 값 두 번 적지 않기).
import product          # 제품 고유값 모음 — 기본값 500pro
from shape_common import SCR
FAB = product.FAB               # 제품별 OBJ 출력 폴더 (500pro=fab_models, 400q=fab_models\400q)
MAN = product.MANIFEST          # 제품별 manifest 파일 (500pro=manifest.json, 400q=manifest_400q.json)
# FAB_ROOT 는 manifest 안의 상대경로('fab_models/xxx.obj')를 붙이는 기준, 즉 리포지토리 루트다.
# FAB 이 제품 하위폴더로 내려가도 기준은 바뀌면 안 되므로 dirname(FAB) 대신 ROOT 를 쓴다.
FAB_ROOT = product.ROOT
SRC = product.SRC_DWG
PN = product.PN

def channel_note(r):
    """형강 note 원문 — 등록·갱신 양쪽에서 같은 문구를 쓴다."""
    ceo = r.get('ceo') or []
    n = ('형강(ㄷ형강 채널) — 규격 "%s" 의 단면(춤 250 x 폭 90 x 두께 %sT)을 만들고, '
         '도면 옆면도(높이 250)의 실제 폐곡선과 평면도(높이 90) 윤곽으로 잘라냈다. '
         '만드는 방식: %s. 길이 %.1fmm, 근거: %s '
         '(치수문자는 DXF 의 DIMENSION 안에 있어 텍스트로 안 뽑히므로 숫자를 추측하지 않고 형상을 쟀다). '
         '사선컷·장공 반영: 옆면 윤곽의 비직교 변 %d개(끝단 사선절단·노치), '
         '웨브(250면) 관통 %d개, 플랜지(90면) 관통 %d개. watertight=%s. '
         '게이트: 소유권(최근접 콜아웃 일치) 통과. '
         # 규격 표기를 어디서 얻었는지는 제품마다 다르다. 출처를 지어내지 않도록 product 에서 가져온다.
         # (출처 문구를 먼저 따로 완성해서 넣는다 — 문자열 이어붙이기와 % 를 섞으면
         #  % 가 먼저 묶여 SPEC_SRC 하나에만 인자가 적용돼 TypeError 가 난다.)
         '규격 근거: %s'
         % (r.get('spec', ''), r['thk'], r.get('profile', ''), r['length'], r['length_src'],
            r.get('ndiag', 0), r.get('nweb', 0), r.get('nflange', 0), r['watertight'],
            product.SPEC_SRC % r.get('spec', '')))
    if ceo:
        n += ' [CEO확인] ' + ' / '.join(ceo)
    return n

def plate_note(r):
    """판재 note 원문 — 등록·갱신 양쪽에서 같은 문구를 쓴다."""
    ev = r.get('evidence', '')
    if ev.startswith('VLM판독:'):
        근거 = ('두께 근거: %s — 단품도 시트를 그림으로 직접 읽어(VLM) 확정한 값. '
              '텍스트 파싱이 도번줄과 두께줄을 묶지 못했을 뿐, 도면에 원래 적혀 있던 표기다.' % ev)
    elif ev.startswith('BOM:'):
        근거 = '두께 근거: 부품표(BOM) 규격칸 원문 "%s".' % ev[4:].strip()
    else:
        근거 = '두께 근거: 도면 콜아웃 원문 "%s".' % ev
    n = ('두께 %sT — %s 2D 절단도 외곽을 압출. '
         'watertight=%s, 홀 %d개, 내부컷 %d개. '
         '게이트: 외곽/덩어리 bbox 일치, 표제란 글자 없음(도면틀 배제), '
         '소유권(최근접 콜아웃 일치) 통과.'
         % (r['thk'], 근거, r['watertight'], r['nholes'], r['ninner']))
    if '절곡' in ev:
        n += ' 절곡 전개형 — 접힘은 재현하지 않고 전개(평판) 상태로만 만든 부재다.'
    return n


# 새 제품의 첫 등록이면 manifest 가 아직 없다. 빈 껍데기만 만든다(기존 제품 파일은 손대지 않음).
if not os.path.exists(MAN):
    json.dump({'items': []}, open(MAN, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
    print('새 manifest 생성 ->', MAN)

bk = MAN + '.bak_' + time.strftime('%Y%m%d_%H%M%S')
shutil.copy2(MAN, bk)
print('manifest 백업 ->', os.path.basename(bk))

man = json.load(open(MAN, encoding='utf-8'))
have_file = {it.get('file') for it in man['items']}
have_pn = set()
for it in man['items']:
    m = PN.search((it.get('name') or '') + ' ' + (it.get('file') or ''))
    if m:
        have_pn.add(m.group())

res = [r for r in json.load(open(SCR + r'\multi_result.json', encoding='utf-8')) if r['status'] == 'ok']
# 형강(pass9_channel)은 만드는 방식이 달라 결과 파일이 따로다. 있으면 같이 등록한다.
_ch = SCR + r'\channel_result.json'
if os.path.exists(_ch):
    res += [r for r in json.load(open(_ch, encoding='utf-8')) if r['status'] == 'ok']
added = 0
updated = 0
UPD = '--update' in sys.argv
# 판재는 기본이 '추가만' 이다. 이미 등록된 판재를 고쳐 쓰는 것은 오인식 교정처럼 근거가
# 분명할 때뿐이므로, 도번을 하나하나 적어 준 경우에만 갱신한다(전체 일괄 갱신 금지).
UPD_PN = set()
for a in sys.argv[1:]:
    if a.startswith('--update-pn='):
        UPD_PN |= {s.strip() for s in a.split('=', 1)[1].split(',') if s.strip()}
for r in res:
    if r['file'] in have_file or r['pn'] in have_pn:
        if UPD and (r.get('kind') == '채널형강' or r['pn'] in UPD_PN):
            for it in man['items']:
                _m = PN.search((it.get('name') or '') + ' ' + (it.get('file') or ''))
                if _m and _m.group() == r['pn']:
                    was = it.get('size_mm')
                    it['size_mm'] = r['extents']; it['faces'] = r['faces']
                    if r.get('kind') == '채널형강':
                        it['note'] = channel_note(r)
                    else:
                        it['note'] = (plate_note(r) +
                                      ' 오인식 교정: 이전 크기 %s → 새 크기 %s. '
                                      '예전 윤곽 재구성이 최근접 덩어리를 오인식해 엉뚱한 덩어리를 '
                                      '부재로 채택했던 것을 바로잡았다(이전 파일은 '
                                      'fab_models\\_구버전_오인식\\ 에 보존).' % (was, r['extents']))
                    _p = os.path.join(FAB_ROOT,
                                      r['file'].replace('/', os.sep))
                    if os.path.exists(_p):
                        it['mb'] = round(os.path.getsize(_p) / 1048576, 2)
                    print('  갱신:', r['pn'], was, '->', r['extents'])
                    updated += 1
                    break
            continue
        print('  이미 등록된 도번/파일, 건너뜀:', r['pn'], r['file']); continue
    p = os.path.join(product.ROOT, r['file'].replace('/', '\\'))
    if not os.path.exists(p):
        print('  파일 없음, 건너뜀:', r['file']); continue
    if r.get('kind') == '채널형강':
        note = channel_note(r)
        if '절곡' in r.get('evidence', ''):
            note += ' 절곡 전개형 — 접힘은 재현하지 않고 전개(평판) 상태로만 만든 부재다.'
    else:
        note = plate_note(r)
    man['items'].append(dict(
        name=product.LABEL + ' / ' + r['pn'],
        file=r['file'],
        src=SRC,
        mb=round(os.path.getsize(p) / 1048576, 2),
        size_mm=r['extents'],
        faces=r['faces'],
        note=note,
    ))
    have_pn.add(r['pn'])
    added += 1
    if added % 10 == 0:
        print('  ... %d개 추가 진행중' % added)
    print('  추가:', r['pn'], r['file'], r['extents'], r['thk'], 'T')

man['updated'] = time.strftime('%Y-%m-%d %H:%M')
json.dump(man, open(MAN, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
print('추가 %d건, 갱신 %d건, 총 %d건' % (added, updated, len(man['items'])))
