#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""报销助手 · 共用核心：路径、台账读写、ID 生成、文件哈希

框架约定（所有脚本共用）：
  报销助手/
    数据/报销台账.json      ← 唯一主数据（发票 + 报销单 + 汇总）
    数据/规则库.json        ← 校验规则（未配置项不做判定）
    数据/收件箱/            ← 待处理票据（拖进来即处理）
    数据/收件箱/已处理/     ← 处理完归档（保留原始文件可追溯）
    数据/日志/              ← 每次解析/校验的日志
    脚本/                   ← 解析、校验、页面生成
    工具/报销助手.html       ← 自包含可编辑页面
"""
import os
import json
import hashlib
import datetime

# ── 多用户支持：BAOYU_EXPENSE_HOME 指定用户工作区，缺省为本目录（刘新元本机）──
_DEFAULT_BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))   # 报销助手/
BASE = os.environ.get('BAOYU_EXPENSE_HOME') or _DEFAULT_BASE
SHARED = os.environ.get('BAOYU_EXPENSE_SHARED') or os.path.join(_DEFAULT_BASE, '共享')
DATA = os.path.join(BASE, '数据')
INBOX = os.path.join(DATA, '收件箱')
DONE = os.path.join(INBOX, '已处理')
LOGDIR = os.path.join(DATA, '日志')
LEDGER = os.path.join(DATA, '报销台账.json')
RULES = os.path.join(DATA, '规则库.json')
SHARED_RULES = os.path.join(SHARED, '规则库.json')
TOOLS = os.path.join(BASE, '工具')
PACK = os.path.join(BASE, '打印包')
# OCR 二进制：共享目录优先（重启不丢），/tmp 兜底
OCR_BIN = os.environ.get('BAOYU_OCR_BIN') or os.path.join(SHARED, 'bin', 'baoyu_ocr_pdf')
if not os.path.exists(OCR_BIN):
    _fallback = '/tmp/baoyu_ocr_pdf'
    if os.path.exists(_fallback):
        OCR_BIN = _fallback

for d in (DATA, INBOX, DONE, LOGDIR, TOOLS, PACK):
    os.makedirs(d, exist_ok=True)

EMPTY_LEDGER = {
    'version': 1,
    'updated': '',
    '发票': [],
    '报销单': [],
    '汇总': {},
}


def now():
    return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')


def today():
    return datetime.date.today().strftime('%Y-%m-%d')


def load_ledger():
    if os.path.exists(LEDGER):
        try:
            return json.load(open(LEDGER, encoding='utf-8'))
        except Exception:
            pass
    return dict(EMPTY_LEDGER)


def save_ledger(led):
    led['updated'] = now()
    led['汇总'] = summarize(led)
    tmp = LEDGER + '.tmp'
    json.dump(led, open(tmp, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
    os.replace(tmp, LEDGER)
    return led


def load_rules():
    """用户目录优先，其次共享规则库（公司制度统一维护）"""
    for p in (RULES, SHARED_RULES):
        if os.path.exists(p):
            try:
                return json.load(open(p, encoding='utf-8'))
            except Exception:
                pass
    return {}


def file_hash(path):
    h = hashlib.sha256()
    with open(path, 'rb') as f:
        for chunk in iter(lambda: f.read(65536), b''):
            h.update(chunk)
    return 'sha256:' + h.hexdigest()[:16]


def next_id(led, prefix='INV'):
    """INV-20260919-0001"""
    day = datetime.date.today().strftime('%Y%m%d')
    stem = '%s-%s-' % (prefix, day)
    n = 1
    for r in led.get('发票', []):
        i = str(r.get('id', ''))
        if i.startswith(stem):
            try:
                n = max(n, int(i[len(stem):]) + 1)
            except ValueError:
                pass
    return stem + '%04d' % n


def is_configured(v):
    """规则项是否已配置（[待填]/null/空 均视为未配置 → 不做判定）"""
    if v is None or v == '':
        return False
    if isinstance(v, str) and ('待填' in v or '待确认' in v):
        return False
    return True


def summarize(led):
    """汇总：按 费用类别 / 月份 / 状态 聚合（页面与推送共用）"""
    by_cat, by_month, by_status = {}, {}, {}
    total = 0.0
    n_doc, n_att = 0, 0
    for r in led.get('发票', []):
        if r.get('类型') == '附件':
            n_att += 1
            continue
        n_doc += 1
        amt = float(r.get('价税合计') or 0)
        total += amt
        c = (r.get('分类') or {}).get('费用类别') or '未分类'
        by_cat[c] = by_cat.get(c, 0) + amt
        m = (r.get('报销期间') or (r.get('开票日期') or '')[:7]) or '未知'
        by_month[m] = by_month.get(m, 0) + amt
        s = (r.get('校验') or {}).get('状态') or '未校验'
        by_status[s] = by_status.get(s, 0) + 1
    return {
        '票据数': n_doc,
        '附件数': n_att,
        '合计': round(total, 2),
        '按类别': {k: round(v, 2) for k, v in sorted(by_cat.items(), key=lambda x: -x[1])},
        '按月': {k: round(v, 2) for k, v in sorted(by_month.items())},
        '按状态': by_status,
    }


def log(name, content):
    p = os.path.join(LOGDIR, '%s_%s.log' % (name, datetime.date.today().strftime('%Y%m%d')))
    with open(p, 'a', encoding='utf-8') as f:
        f.write('[%s] %s\n' % (now(), content))


if __name__ == '__main__':
    print('报销助手 · 路径检查')
    for k, v in [('BASE', BASE), ('数据', DATA), ('收件箱', INBOX), ('已处理', DONE),
                 ('台账', LEDGER), ('规则库', RULES)]:
        print('  %-6s %s  %s' % (k, '✅' if os.path.exists(v) else '❌', v))
    led = load_ledger()
    print('  当前台账：%d 张票据，%d 张报销单' % (len(led.get('发票', [])), len(led.get('报销单', []))))
