#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""抽出 2026Q3 汇报 PPT 里嵌入的 Excel 并读结构。

产物：~/Desktop/Hermes输出-工作类/经营分析/2026Q3汇报_嵌入Excel/<部门>/<汇报人>_<工作簿>.xlsx|.xls
规则：嵌入对象是 zip → 直接当 .xlsx 读；是 OLE(D0CF11E0) → 存成 .xls 用 xlrd 读。
"""
import io
import os
import subprocess
import zipfile

import pandas as pd

_BASE = '/Users/liuxinyuan/Desktop/hermas输入-工作台数据库/2026年3季度汇报'
# 源目录优先级：环境变量 Q3_SRC（指向已物化的本地副本）> <base>/2026年3季度汇报 > <base>
_LOCAL = os.path.expanduser('~/.hermes/profiles/zone-b/cache/scratch/q3_src_local')
if os.environ.get('Q3_SRC'):
    ROOT = os.environ['Q3_SRC']
elif os.path.isdir(_LOCAL):
    ROOT = _LOCAL
elif os.path.isdir(os.path.join(_BASE, '2026年3季度汇报')):
    ROOT = os.path.join(_BASE, '2026年3季度汇报')
else:
    ROOT = _BASE
OUT = '/Users/liuxinyuan/Desktop/Hermes输出-工作类/经营分析/2026Q3汇报_嵌入Excel'
os.makedirs(OUT, exist_ok=True)
print('源目录：%s' % ROOT)

rows = []
for dept in sorted(os.listdir(ROOT)):
    pd_ = os.path.join(ROOT, dept)
    if not os.path.isdir(pd_):
        continue
    for root, dirs, fs in os.walk(pd_):
        for fn in sorted(fs):
            if fn.startswith('.') or not fn.lower().endswith('.pptx'):
                continue
            src = os.path.join(root, fn)
            who = fn.replace('.pptx', '')
            try:
                z = zipfile.ZipFile(src)
            except Exception as e:
                print('✗ %s 打不开：%s' % (fn, e))
                continue
            emb = [n for n in z.namelist() if n.startswith('ppt/embeddings/') and not n.endswith('/')]
            outdir = os.path.join(OUT, dept)
            os.makedirs(outdir, exist_ok=True)
            for n in emb:
                raw = z.read(n)
                base = os.path.basename(n)
                is_zip = raw[:4] == b'PK\x03\x04'
                dst = os.path.join(outdir, '%s__%s' % (who[:28], base if is_zip else base.replace('.xlsx', '.xls')))
                open(dst, 'wb').write(raw)
                info = {'部门': dept, '汇报人': who, '对象': base,
                        '格式': 'xlsx' if is_zip else 'xls(OLE)', '大小KB': round(len(raw) / 1024.0, 1)}
                try:
                    sheets = pd.read_excel(dst, sheet_name=None, header=None, nrows=60)
                    info['工作表'] = list(sheets.keys())
                    info['形状'] = {k: '%d×%d' % (v.shape[0], v.shape[1]) for k, v in sheets.items()}
                except Exception as e:
                    info['读失败'] = str(e)[:70]
                rows.append(info)
                print('· %-30s %-34s %-9s %s' % (who[:28], base[:33], info['格式'], info.get('形状') or info.get('读失败')))

# ② 独立投递的 Excel（不在 PPT 内嵌里）也一并收编，供归一脚本读取
import shutil
stand = []
for root, dirs, fs in os.walk(ROOT):
    dept = os.path.basename(os.path.dirname(root)) if os.path.basename(root) and os.path.dirname(root) else os.path.basename(root)
    # 部门 = 相对 ROOT 的第一层目录名
    rel_root = os.path.relpath(root, ROOT)
    dept = rel_root.split(os.sep)[0] if rel_root != '.' else ''
    for fn in sorted(fs):
        low = fn.lower()
        if fn.startswith('.') or not low.endswith(('.xlsx', '.xls')):
            continue
        src = os.path.join(root, fn)
        outdir = os.path.join(OUT, dept) if dept else OUT
        os.makedirs(outdir, exist_ok=True)
        dst = os.path.join(outdir, fn.rstrip('.xls').rstrip('.xlsx') + '__原表' + os.path.splitext(fn)[1])
        try:
            shutil.copy2(src, dst)
            stand.append(os.path.relpath(dst, OUT))
            print('· 独立表 %-52s → %s' % (fn[:52], os.path.relpath(dst, OUT)))
        except Exception as e:
            print('✗ 独立表复制失败 %s：%s' % (fn, e))

df = pd.DataFrame(rows)
df.to_excel(os.path.join(OUT, '_嵌入对象清单.xlsx'), index=False)
print()
print('嵌入对象 %d 个 ｜ 涉及 PPT %d 份 ｜ 独立投递表 %d 份 ｜ 抽出到 %s'
      % (len(df), df['汇报人'].nunique() if len(df) else 0, len(stand), OUT))
