# 폴더 안의 엑셀 파일(.xlsx)을 한 파일로 합친다.
# 사용법: python merge.py <폴더 경로>   → 그 폴더 바로 바깥에 '<폴더이름>_합친결과.xlsx'를 만든다.
#   (결과를 같은 폴더에 두면 다음 실행 때 결과 파일까지 합쳐지므로 바깥에 저장한다)
# - 열은 이름으로 맞춘다(순서가 달라도 된다).
# - 머리글 이름이 다른 경우는 아래 '같은 열로 볼 이름'에 추가한다.
# - 빈 행, '합계'·'소계'·'총계' 행(띄어쓰기 무시), 엑셀 잠금 파일(~$로 시작)은 건너뛴다.
# - 빈 칸(병합 셀, 저장 안 된 수식)이나 문자로 된 날짜·숫자가 있는 행은 합치되 '확인 필요'로 알려 준다.
import sys, time
from pathlib import Path
from openpyxl import load_workbook, Workbook

COLUMNS = ['날짜', '지점', '품목', '수량', '단가', '금액']   # 결과 파일의 열 순서
ALIASES = {'판매수량': '수량'}                              # 같은 열로 볼 이름
SKIP_WORDS = {'합계', '소계', '총계'}                       # 이 값이 든 행은 건너뛴다

def main(folder: Path) -> None:
    start = time.perf_counter()
    out = Workbook(); ws_out = out.active; ws_out.title = '합친결과'
    ws_out.append(COLUMNS + ['원본파일'])
    report = []  # (파일, 가져온 행, 건너뛴 행, 문제)
    for path in sorted(folder.glob('*.xlsx')):
        if path.name.startswith('~$'):
            continue
        try:
            ws = load_workbook(path, read_only=True, data_only=True).worksheets[0]
        except Exception:
            report.append((path.name, 0, 0, '열 수 없음: 암호·DRM이 걸렸거나 손상된 파일')); continue
        rows = ws.iter_rows(values_only=True)
        header = [ALIASES.get(str(h).strip(), str(h).strip()) if h is not None else '' for h in next(rows, ())]
        missing = [c for c in COLUMNS if c not in header]
        if missing:
            report.append((path.name, 0, 0, f'없는 열: {", ".join(missing)}'))
            continue
        idx = [header.index(c) for c in COLUMNS]
        taken = skipped = odd = 0
        for r in rows:
            if r is None or all(v in (None, '') for v in r):
                skipped += 1; continue          # 빈 행
            if any(str(v).replace(' ', '') in SKIP_WORDS for v in r if v is not None):
                skipped += 1; continue          # 합계 행 (열 순서가 달라도 잡히도록 모든 칸을 본다)
            r = r + (None,) * (len(header) - len(r))   # 끝 칸이 빈 행은 짧게 읽힐 수 있다
            vals = [r[k] for k in idx]
            if any(v in (None, '') for v in vals) or any(isinstance(v, str) for v in vals[:1] + vals[3:]):
                odd += 1                            # 빈 칸(병합 셀·수식) 또는 문자로 된 날짜·숫자
            ws_out.append(vals + [path.name])
            taken += 1
        report.append((path.name, taken, skipped, f'빈 칸·문자로 된 숫자/날짜가 있는 행 {odd}개' if odd else ''))
    # 날짜 열이 좁으면 엑셀에서 '#######'로 보이므로 서식과 너비를 지정한다
    for (cell,) in ws_out.iter_rows(min_row=2, min_col=1, max_col=1):
        cell.number_format = 'yyyy-mm-dd'
    ws_out.column_dimensions['A'].width = 12
    ws_out.column_dimensions['G'].width = 24
    result = folder.resolve().parent / f'{folder.resolve().name}_합친결과.xlsx'
    try:
        out.save(result)
    except PermissionError:
        sys.exit(f'{result.name} 파일을 저장하지 못했습니다. 엑셀에서 열려 있으면 닫고 다시 실행하세요.')
    sec = time.perf_counter() - start

    total = sum(t for _, t, _, _ in report)
    problems = [r for r in report if r[3]]
    print(f'파일 {len(report)}개, 가져온 행 {total}개, 건너뛴 행 {sum(s for _, _, s, _ in report)}개, {sec:.2f}초 → {result.name}')
    for name, _, _, why in problems:
        print(f'  확인 필요: {name} ({why})')
    for p in folder.glob('*.xls*'):
        if p.suffix.lower() != '.xlsx' and not p.name.startswith('~$'):
            print(f'  합치지 않음: {p.name} (.xlsx로 다시 저장하면 합쳐집니다)')

if __name__ == '__main__':
    if len(sys.argv) < 2:
        sys.exit('사용법: python merge.py <폴더 경로>')
    folder = Path(sys.argv[1].strip('"'))   # PowerShell은 "폴더\" 끝에 "를 붙여 넘긴다
    if not folder.is_dir():
        sys.exit(f'폴더를 찾지 못했습니다: {folder}')
    main(folder)
