"""Excel输出：工具函数 + 各类sheet生成"""
import openpyxl
from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
from collections import defaultdict
from calc_engine import RULES, DAYS

hf = Font(bold=True)
hfl = PatternFill(start_color='D9E1F2', end_color='D9E1F2', fill_type='solid')
bd = Border(left=Side(style='thin'),right=Side(style='thin'),top=Side(style='thin'),bottom=Side(style='thin'))

def WH(ws, headers, row=1):
    for c, h in enumerate(headers, 1):
        cl = ws.cell(row=row, column=c, value=h)
        cl.font=hf; cl.fill=hfl; cl.border=bd; cl.alignment=Alignment(horizontal='center', wrap_text=True)

def WR(ws, rn, vals):
    for c, v in enumerate(vals, 1):
        cl = ws.cell(row=rn, column=c, value=v); cl.border=bd

def AW(ws):
    for col in ws.columns:
        ml = max((len(str(c.value or '')) for c in col), default=0)
        ws.column_dimensions[col[0].column_letter].width = min(ml+3, 22)

def R(v, n=2):
    return round(v, n) if isinstance(v, (int,float)) and v else v

def agg(dl):
    bp = defaultdict(lambda: {'n':0,'a':0})
    for d in dl: bp[d['销售']]['n']+=1; bp[d['销售']]['a']+=d['额']
    return dict(bp)

def write_sec(ws, rn, title, dl):
    ws.cell(row=rn, column=1, value=title).font=Font(bold=True, size=11); rn+=1
    WH(ws, ['销售人员','车辆数','金额'], rn); rn+=1
    bp=agg(dl); tv=ta=0
    for p in sorted(bp.keys()):
        WR(ws,rn,[p,bp[p]['n'],R(bp[p]['a'])]); tv+=bp[p]['n']; ta+=bp[p]['a']; rn+=1
    WR(ws,rn,['总计',tv,R(ta)]); ws.cell(row=rn,column=1).font=hf; return rn+2

def write_total(ws, rn, month, all_data):
    total_bp = defaultdict(lambda: {'部门':'','额':0})
    for cat,dl in all_data.items():
        for d in dl: total_bp[d['销售']]['额']+=d['额']; total_bp[d['销售']]['部门']=d['部门']
    ws.cell(row=rn,column=1,value=f'{month}月合计应发奖励（按销售人员）').font=Font(bold=True,size=11); rn+=1
    WH(ws,['销售人员','部门名称','合计应发奖励'],rn); rn+=1
    gt=0
    for p in sorted(total_bp.keys()):
        WR(ws,rn,[p,total_bp[p]['部门'],R(total_bp[p]['额'])]); gt+=total_bp[p]['额']; rn+=1
    WR(ws,rn,['合计','',R(gt)]); ws.cell(row=rn,column=1).font=hf; rn+=2
    by_dept=defaultdict(float)
    for p,d in total_bp.items(): by_dept[d['部门']]+=d['额']
    ws.cell(row=rn,column=1,value=f'{month}月合计应发奖励（按部门）').font=Font(bold=True,size=11); rn+=1
    WH(ws,['部门名称','合计应发奖励'],rn); rn+=1
    for dept in sorted(by_dept.keys()): WR(ws,rn,[dept,R(by_dept[dept])]); rn+=1
    WR(ws,rn,['合计',R(gt)]); ws.cell(row=rn,column=1).font=hf

# ============================================================
# Sheet生成函数
# ============================================================

def write_rules_sheet(wb):
    ws = wb.active; ws.title='考核奖励规则'
    WH(ws,['考核目标','月度目标里程(km)','奖励金额(元)'])
    for i,(n,km,b) in enumerate([('交投40辆4.5T普货',3000,150),('交投190辆4.5T冷链车',3000,150),
        ('羚牛136辆4.5T冷链车',5000,260),('恒运50辆4.5T普货',5000,260),('羚牛100辆18T',6000,1000)],2):
        WR(ws,i,[n,km,b])
    AW(ws)

def write_detail_sheet(wb, records, month):
    ws = wb.create_sheet(f'里程明细{month}月')
    WH(ws,['车牌号','部门名称','销售经理','客户名称','合同编号','考核目标','月度目标里程','对应月奖励金额',
            '考核天数',f'{month}月应考核里程',f'{month}月实际行驶里程','完成率',f'{month}月是否达标',
            f'{month}月奖金(天数折算)','多跑里程','可结转月数','考核状态'])
    rn=2
    for r in sorted(records, key=lambda x: (x['销售经理'],x['车牌号'])):
        t,a = r['应考核里程(km)'], r['实际行驶里程(km)']
        WR(ws,rn,[r['车牌号'],r['部门名称'],r['销售经理'],r.get('客户名称',''),r.get('合同编号',''),
            r.get('考核目标',''),r['月度目标里程'],r['对应月奖励金额'],r['考核天数'],
            R(t),R(a),R(a/t,4) if t>0 else 0,r['是否达标'],R(r['奖金']),R(r['多跑']),r['可结转'],
            r.get('考核状态','')]); rn+=1
    AW(ws)

def write_calc_process_jan(wb, G1):
    ws = wb.create_sheet('1月计算过程')
    WH(ws,['车牌号','销售经理','部门','①记录数','②总考核天数','③总应考核里程','④总实际里程',
            '⑤有达标记录','⑥达标记录奖金合计','⑦总多跑里程','⑧月度目标里程','⑨可结转月数=floor(⑦/⑧)',
            '→1月发放金额','→发放类型'])
    rn=2
    for k in sorted(G1.keys(), key=lambda x: (x[1],x[0])):
        g=G1[k]
        excess=sum(r['多跑'] for r in g['recs'] if r['是否达标']=='达标')
        WR(ws,rn,[k[0],k[1],g['部门'],len(g['recs']),g['天数'],R(g['应考核']),R(g['实际']),
            '是' if g['有达标'] else '否',R(g['奖金']),R(excess),g['目标km'],g['可结转'],
            R(g['奖金']) if g['有达标'] else 0,'当月达标' if g['有达标'] else '未达标']); rn+=1
    AW(ws)

def write_calc_process_feb(wb, G1, G2):
    ws = wb.create_sheet('2月计算过程')
    WH(ws,['车牌号','销售经理','部门',
        '1月总应考核','1月总实际','1月有达标','1月奖金','1月多跑','1月可结转',
        '2月记录数','2月总天数','2月总应考核','2月总实际','2月有达标','2月达标奖金',
        '累计应完成','累计实际','累计是否达标',
        '判断①结转','→结转金额(完整月)','判断②补发1月','→补发1月金额',
        '判断③当月','→2月当月金额','判断④累计补发2月','→累计补发2月金额','2月发放合计'])
    rn=2
    for k in sorted(G2.keys(), key=lambda x: (x[1],x[0])):
        g2=G2[k]; g1=G1.get(k)
        j_q=g1['有达标'] if g1 else False; j_c=g1['可结转'] if g1 else 0
        j_t=g1['应考核'] if g1 else 0; j_a=g1['实际'] if g1 else 0
        j_bonus=g1['奖金'] if g1 else 0
        je=sum(r['多跑'] for r in g1['recs'] if r['是否达标']=='达标') if g1 else 0
        ct=g2.get('cum_t',0); ca=g2.get('cum_a',0); cq=g2.get('cum_q',False)
        carry=g2.get('结转',0); bp1=g2.get('补发1月',0); bonus2=g2.get('当月奖金',0); cbp2=g2.get('累计补发2月',0)
        c1=f"1月达标={j_q},可结转={j_c}→{'是' if carry>0 else '否'}"
        c2=f"1月未达标={not j_q},累计达标={cq}→{'是' if bp1>0 else '否'}" if g1 else "无1月"
        c3=f"2月达标={g2['有达标']},无结转={carry==0}→{'是' if bonus2>0 else '否'}"
        c4=f"2月未达标={not g2['有达标']},无结转={carry==0},累计达标={cq}→{'是' if cbp2>0 else '否'}"
        total=carry+bp1+bonus2+cbp2
        WR(ws,rn,[k[0],k[1],g2['部门'],R(j_t),R(j_a),'是' if j_q else '否',R(j_bonus),R(je),j_c,
            len(g2['recs']),g2['天数'],R(g2['应考核']),R(g2['实际']),'是' if g2['有达标'] else '否',R(g2['奖金']),
            R(ct),R(ca),'达标' if cq else '未达标',
            c1,R(carry) if carry>0 else 0,c2,R(bp1) if bp1>0 else 0,
            c3,R(bonus2) if bonus2>0 else 0,c4,R(cbp2) if cbp2>0 else 0,R(total) if total>0 else 0]); rn+=1
    AW(ws)

def write_calc_process_mar(wb, G1, G2, G3, feb_data):
    ws = wb.create_sheet('3月计算过程')
    WH(ws,['车牌号','销售经理','部门',
        '1月应考核','1月实际','1月有达标','1月奖金已发',
        '2月应考核','2月实际','2月有达标','2月奖金已发',
        '3月记录数','3月总天数','3月总应考核','3月总实际','3月有达标','3月达标奖金',
        '累计应完成','累计实际','累计是否达标',
        '判断①结转','→结转金额','判断②补发1月','→补发1月金额',
        '判断③补发2月','→补发2月金额','判断④当月','→3月当月金额',
        '判断⑤累计补发3月','→累计补发3月金额','3月发放合计'])
    rn=2
    for k in sorted(G3.keys(), key=lambda x: (x[1],x[0])):
        g3=G3[k]; g2=G2.get(k); g1=G1.get(k)
        j_t=g1['应考核'] if g1 else 0; j_a=g1['实际'] if g1 else 0
        j_q=g1['有达标'] if g1 else False; j_paid=(g1['奖金']>0) if g1 else False
        if g1 and j_q: j_paid=True
        if g2 and g2.get('1月已补发',False): j_paid=True
        f_t=g2['应考核'] if g2 else 0; f_a=g2['实际'] if g2 else 0
        f_q=g2['有达标'] if g2 else False; f_paid=g2['2月已发'] if g2 else False
        f_carry=g2['可结转'] if g2 else 0
        ct=g3.get('cum_t',0); ca=g3.get('cum_a',0); cq=g3.get('cum_q',False)
        carry=g3.get('结转',0); bj=g3.get('补发1月',0); bf2=g3.get('补发2月',0)
        bonus3=g3.get('当月奖金',0); cbp3=g3.get('累计补发3月',0)
        c1=f"2月可结转={f_carry}→{'是' if carry>0 else '否'}"
        c2=f"1月未发={not j_paid},累计达标={cq}→{'是' if bj>0 else '否'}"
        c3=f"2月未发={not f_paid},累计达标={cq}→{'是' if bf2>0 else '否'}"
        c4=f"3月达标={g3['有达标']},无结转={carry==0}→{'是' if bonus3>0 else '否'}"
        c5=f"3月未达标={not g3['有达标']},无结转={carry==0},累计达标={cq}→{'是' if cbp3>0 else '否'}"
        total=carry+bj+bf2+bonus3+cbp3
        WR(ws,rn,[k[0],k[1],g3['部门'],R(j_t),R(j_a),'是' if j_q else '否','是' if j_paid else '否',
            R(f_t),R(f_a),'是' if f_q else '否','是' if f_paid else '否',
            len(g3['recs']),g3['天数'],R(g3['应考核']),R(g3['实际']),'是' if g3['有达标'] else '否',R(g3['奖金']),
            R(ct),R(ca),'达标' if cq else '未达标',
            c1,R(carry) if carry>0 else 0,c2,R(bj) if bj>0 else 0,
            c3,R(bf2) if bf2>0 else 0,c4,R(bonus3) if bonus3>0 else 0,
            c5,R(cbp3) if cbp3>0 else 0,R(total) if total>0 else 0]); rn+=1
    AW(ws)

def write_summary_jan(wb, records, loss_data=None, plate_client=None):
    ws = wb.create_sheet('1月汇总')
    jan_dl=[{'车牌':r['车牌号'],'销售':r['销售经理'],'部门':r['部门名称'],'额':r['奖金']} for r in records if r['是否达标']=='达标']
    rn=write_sec(ws,1,'1月达标奖励(考核应发)',jan_dl)

    if loss_data is not None:
        # 亏损拦截
        blocked = []
        passed = []
        unmatched = []
        for d in jan_dl:
            client = (plate_client or {}).get(d['车牌'], '')
            status = loss_data.get(client, '未匹配') if client else '未匹配'
            if status == '是':
                blocked.append({**d, '客户': client})
            elif status == '未匹配':
                unmatched.append({**d, '客户': client})
            else:
                passed.append(d)

        rn = write_sec(ws, rn, '亏损拦截(客户亏损不发放)', blocked if blocked else [])
        rn = write_sec(ws, rn, '未匹配亏损表(需人工确认)', unmatched if unmatched else [])
        rn = write_sec(ws, rn, '最终发放', passed)

        ws.cell(row=rn, column=1, value='汇总').font=Font(bold=True, size=11); rn+=1
        total_考核 = sum(d['额'] for d in jan_dl)
        total_拦截 = sum(d['额'] for d in blocked)
        total_未匹配 = sum(d['额'] for d in unmatched)
        total_最终 = sum(d['额'] for d in passed)
        WR(ws, rn, ['考核应发', R(total_考核)]); rn+=1
        WR(ws, rn, ['亏损拦截', R(total_拦截)]); rn+=1
        WR(ws, rn, ['未匹配(待确认)', R(total_未匹配)]); rn+=1
        WR(ws, rn, ['最终发放', R(total_最终)]); ws.cell(row=rn,column=1).font=Font(bold=True); rn+=2

    write_total(ws,rn,1,{'达标':jan_dl})
    AW(ws)

def build_payment_records(month, month_data, all_loss_data, plate_client):
    """构建奖金发放记录列表，每条考核应发一行，叠加亏损筛选。
    all_loss_data: {1: loss_dict, 2: loss_dict, 3: loss_dict_or_None}
    补发X月 → 查X月盈亏；其他 → 查当月盈亏；无客户 → 正常发放
    """
    # 发放类型→查哪个月盈亏
    def get_loss_month(cat, settle_month):
        if '补发1月' in cat: return 1
        if '补发2月' in cat: return 2
        if '补发3月' in cat: return 3
        return settle_month

    records = []
    for cat, dl in month_data.items():
        loss_month = get_loss_month(cat, month)
        loss_data = all_loss_data.get(loss_month)

        for d in dl:
            client = (plate_client or {}).get(d['车牌'], '')

            # 无客户关联（如虚拟结转记录）→ 正常发放
            if not client:
                loss_status = '否'
            elif loss_data:
                loss_status = loss_data.get(client, '未匹配')
            else:
                loss_status = '未匹配'  # 无亏损表视为未匹配，不发放

            考核应发 = d['额']
            if loss_status == '是':
                拦截 = 考核应发; 实发 = 0
            elif loss_status == '未匹配':
                拦截 = 考核应发; 实发 = 0
            else:
                拦截 = 0; 实发 = 考核应发

            records.append({
                '车牌号': d['车牌'],
                '业务员': d['销售'],
                '部门': d['部门'],
                '客户名称': client or '(无客户关联)',
                '发放类型': cat,
                '盈亏查询月': f'{loss_month}月',
                '考核应发': 考核应发,
                '客户盈亏': loss_status,
                '亏损拦截': 拦截,
                '实发金额': 实发,
            })
    return records

def write_payment_record_sheet(wb, month, payment_records):
    """写入奖金发放记录sheet"""
    ws = wb.create_sheet(f'{month}月奖金发放记录')

    headers = ['车牌号','业务员','部门','客户名称','发放类型','盈亏查询月',
               '考核应发','客户盈亏','亏损拦截','实发金额']
    WH(ws, headers)

    green_fill = PatternFill(start_color='C6EFCE', end_color='C6EFCE', fill_type='solid')
    red_fill = PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid')
    yellow_fill = PatternFill(start_color='FFFFCC', end_color='FFFFCC', fill_type='solid')

    rn = 2
    for r in sorted(payment_records, key=lambda x: (x['业务员'], x['车牌号'])):
        WR(ws, rn, [r['车牌号'], r['业务员'], r['部门'], r['客户名称'], r['发放类型'],
                     r.get('盈亏查询月',''),
                     R(r['考核应发']), r['客户盈亏'], R(r['亏损拦截']), R(r['实发金额'])])
        if r['客户盈亏'] == '是':
            for ci in [8, 9, 10]: ws.cell(row=rn, column=ci).fill = red_fill
        elif r['客户盈亏'] == '未匹配':
            for ci in [8, 9, 10]: ws.cell(row=rn, column=ci).fill = yellow_fill
        elif r['实发金额'] > 0:
            ws.cell(row=rn, column=10).fill = green_fill
        rn += 1

    total_应发 = sum(r['考核应发'] for r in payment_records)
    total_拦截 = sum(r['亏损拦截'] for r in payment_records)
    total_实发 = sum(r['实发金额'] for r in payment_records)
    rn += 1
    WR(ws, rn, ['', '', '', '', '合计', '', R(total_应发), '', R(total_拦截), R(total_实发)])
    for ci in range(5, 11): ws.cell(row=rn, column=ci).font = Font(bold=True)

    ws.auto_filter.ref = f"A1:J1"
    AW(ws)
    return payment_records

def write_summary_from_records(wb, month, payment_records):
    """从奖金发放记录生成月汇总"""
    ws = wb.create_sheet(f'{month}月汇总')
    rn = 1

    # 按发放类型分section
    by_type = defaultdict(list)
    for r in payment_records:
        by_type[r['发放类型']].append({'车牌':r['车牌号'],'销售':r['业务员'],'部门':r['部门'],'额':r['实发金额']})

    # 考核应发（按类型）
    ws.cell(row=rn, column=1, value='一、考核应发明细').font=Font(bold=True, size=12); rn+=2
    by_type_应发 = defaultdict(list)
    for r in payment_records:
        by_type_应发[r['发放类型']].append({'车牌':r['车牌号'],'销售':r['业务员'],'部门':r['部门'],'额':r['考核应发']})
    for cat in sorted(by_type_应发.keys()):
        rn = write_sec(ws, rn, f'考核应发-{cat}', by_type_应发[cat])
    total_应发 = sum(r['考核应发'] for r in payment_records)
    WR(ws, rn, ['考核应发合计', '', R(total_应发)]); ws.cell(row=rn,column=1).font=Font(bold=True,size=11); rn+=2

    # 亏损拦截
    blocked = [r for r in payment_records if r['客户盈亏'] == '是' and r['考核应发'] > 0]
    unmatched = [r for r in payment_records if r['客户盈亏'] == '未匹配' and r['考核应发'] > 0]
    if blocked or unmatched:
        ws.cell(row=rn, column=1, value='二、亏损筛选').font=Font(bold=True, size=12); rn+=2
        if blocked:
            bl_dl = [{'车牌':r['车牌号'],'销售':r['业务员'],'部门':r['部门'],'额':r['亏损拦截']} for r in blocked]
            rn = write_sec(ws, rn, '亏损拦截(客户亏损不发放)', bl_dl)
        if unmatched:
            um_dl = [{'车牌':r['车牌号'],'销售':r['业务员'],'部门':r['部门'],'额':r['亏损拦截']} for r in unmatched]
            rn = write_sec(ws, rn, '未匹配亏损表(需人工确认)', um_dl)
        total_拦截 = sum(r['亏损拦截'] for r in payment_records)
        WR(ws, rn, ['拦截合计', '', R(total_拦截)]); ws.cell(row=rn,column=1).font=Font(bold=True); rn+=2

    # 最终发放（按销售人员）
    ws.cell(row=rn, column=1, value='三、最终发放').font=Font(bold=True, size=12); rn+=2
    passed = [r for r in payment_records if r['实发金额'] > 0]
    passed_dl = [{'车牌':r['车牌号'],'销售':r['业务员'],'部门':r['部门'],'额':r['实发金额']} for r in passed]
    rn = write_sec(ws, rn, '最终发放明细', passed_dl)

    # 最终发放合计（按销售/按部门）
    total_by_person = defaultdict(lambda: {'部门':'','额':0})
    for r in passed:
        total_by_person[r['业务员']]['额'] += r['实发金额']
        total_by_person[r['业务员']]['部门'] = r['部门']

    ws.cell(row=rn, column=1, value=f'{month}月最终发放（按销售人员）').font=Font(bold=True, size=11); rn+=1
    WH(ws, ['销售人员','部门名称','最终发放'], rn); rn+=1
    gt = 0
    for p in sorted(total_by_person.keys()):
        d = total_by_person[p]
        WR(ws, rn, [p, d['部门'], R(d['额'])]); gt += d['额']; rn+=1
    WR(ws, rn, ['合计','', R(gt)]); ws.cell(row=rn,column=1).font=hf; rn+=2

    by_dept = defaultdict(float)
    for p, d in total_by_person.items(): by_dept[d['部门']] += d['额']
    ws.cell(row=rn, column=1, value=f'{month}月最终发放（按部门）').font=Font(bold=True, size=11); rn+=1
    WH(ws, ['部门名称','最终发放'], rn); rn+=1
    for dept in sorted(by_dept.keys()):
        WR(ws, rn, [dept, R(by_dept[dept])]); rn+=1
    WR(ws, rn, ['合计', R(gt)]); ws.cell(row=rn,column=1).font=hf; rn+=2

    # 汇总数字
    total_实发 = sum(r['实发金额'] for r in payment_records)
    total_拦截 = sum(r['亏损拦截'] for r in payment_records)
    ws.cell(row=rn, column=1, value='总览').font=Font(bold=True, size=12); rn+=1
    WR(ws, rn, ['考核应发', R(total_应发)]); rn+=1
    WR(ws, rn, ['亏损拦截', R(total_拦截)]); rn+=1
    WR(ws, rn, ['最终发放', R(total_实发)]); ws.cell(row=rn,column=1).font=Font(bold=True,size=12)
    ws.cell(row=rn,column=2).font=Font(bold=True,size=12)

    AW(ws)

# 保留旧函数兼容（3月无亏损表时使用）
def write_summary_month(wb, month, month_data, section_names, loss_data=None, plate_client=None):
    ws = wb.create_sheet(f'{month}月汇总')
    rn=1
    for i,cat in enumerate(section_names):
        label_map = {'结转':f'一、结转：{month-1}月多跑在{month}月发',
                     '补发1月':'二、补发1月','补发2月':'三、补发2月',
                     '当月':f'{"三" if month==2 else "四"}、{month}月当月奖励',
                     f'累计补发{month}月':f'{"四" if month==2 else "五"}、累计达标补发{month}月'}
        rn=write_sec(ws,rn,label_map.get(cat,cat),month_data.get(cat,[]))

    # 考核应发合计
    write_total(ws,rn,month,month_data)
    # 找最后一行
    rn = ws.max_row + 2

    if loss_data is not None:
        # 合并所有发放记录
        all_dl = []
        for cat, dl in month_data.items():
            all_dl.extend(dl)

        blocked = []; passed = []; unmatched = []
        for d in all_dl:
            client = (plate_client or {}).get(d['车牌'], '')
            status = loss_data.get(client, '未匹配') if client else '未匹配'
            if status == '是':
                blocked.append(d)
            elif status == '未匹配':
                unmatched.append(d)
            else:
                passed.append(d)

        ws.cell(row=rn, column=1, value='═══ 亏损筛选 ═══').font=Font(bold=True, size=12); rn+=2
        rn = write_sec(ws, rn, '亏损拦截(客户亏损不发放)', blocked)
        rn = write_sec(ws, rn, '未匹配亏损表(需人工确认)', unmatched)
        rn = write_sec(ws, rn, '最终发放', passed)

        total_考核 = sum(d['额'] for d in all_dl)
        total_拦截 = sum(d['额'] for d in blocked)
        total_未匹配 = sum(d['额'] for d in unmatched)
        total_最终 = sum(d['额'] for d in passed)

        ws.cell(row=rn, column=1, value='亏损筛选汇总').font=Font(bold=True, size=11); rn+=1
        WR(ws, rn, ['考核应发合计', R(total_考核)]); rn+=1
        WR(ws, rn, ['亏损拦截金额', R(total_拦截)]); rn+=1
        WR(ws, rn, ['未匹配金额(待确认)', R(total_未匹配)]); rn+=1
        WR(ws, rn, ['最终应发合计', R(total_最终)])
        ws.cell(row=rn,column=1).font=Font(bold=True, size=12)
        ws.cell(row=rn,column=2).font=Font(bold=True, size=12)

    AW(ws)

# ============================================================
# 新增：业务员sheet
# ============================================================

def write_salesperson_sheet(wb, person, dept, settle_month, D, G, month_data, vehicle_payments):
    short_dept = dept.replace('业务','') if '业务' in dept else dept
    ws = wb.create_sheet(f'{short_dept}-{person}')
    ws.cell(row=1,column=1,value=f'{person} | {dept} | {settle_month}月绩效对账单').font=Font(bold=True,size=14)

    plates = set()
    for m in range(1, settle_month+1):
        for k in G.get(m, {}):
            if k[1] == person: plates.add(k[0])

    person_total = sum(d['额'] for cat,dl in month_data.items() for d in dl if d['销售']==person)
    ws.cell(row=2,column=1,value=f'本月考核车辆: {len(plates)}辆 | 本月发放合计: {R(person_total)}元').font=Font(bold=True,size=11)

    # 表头：车辆信息 + 各月里程/目标 + 累计 + 奖金池
    headers = ['车牌号','考核目标','月奖励']
    for m in range(1, settle_month+1):
        headers.append(f'{m}月里程/目标')
    if settle_month >= 2:
        headers += ['累计里程/目标']
    headers.append('达标')
    WH(ws, headers, 4)

    rn = 5
    for plate in sorted(plates):
        g_cur = None
        for m in range(settle_month, 0, -1):
            g_cur = G.get(m, {}).get((plate, person))
            if g_cur: break
        if not g_cur: continue

        if g_cur['recs']:
            first = g_cur['recs'][0]
        else:
            first = {'合同编号':'','客户名称':'(无考核记录)','考核目标':g_cur.get('考核目标','')}
        mkm = g_cur['目标km']

        # 第1行：车辆信息 + 各月里程/目标
        row = [plate, first.get('考核目标',''), g_cur['奖励额']]
        cum_t = 0; cum_a = 0
        for m in range(1, settle_month+1):
            gm = G.get(m, {}).get((plate, person))
            if gm:
                t=gm['应考核']; a=gm['实际']; cum_t+=t; cum_a+=a
                row.append(f'{R(a,0)}/{R(t,0)}')
            else:
                row.append('-')
        if settle_month >= 2:
            row.append(f'{R(cum_a,0)}/{R(cum_t,0)}')
        cum_q = cum_a >= cum_t and cum_t > 0
        # 达标判断：取settle_month的group
        g_s = G.get(settle_month, {}).get((plate, person))
        if g_s and g_s.get('有达标'):
            row.append('达标')
        elif cum_q:
            row.append('累计达标')
        else:
            row.append('未达标')
        WR(ws, rn, row)
        ws.cell(row=rn, column=1).font = Font(bold=True)
        rn += 1

        # 第2-N行：发放明细（历史已发 + 本月发放）
        WH(ws, ['', '发放项', '金额', '说明', '奖金池'], rn); rn += 1

        pays = vehicle_payments.get(plate, [])
        pays_to_date = [p for p in pays if p['结算月'] <= settle_month]
        total_periods = len(pays_to_date)

        # 历史已发（m < settle_month）
        for m in range(1, settle_month):
            gm = G.get(m, {}).get((plate, person))
            # 查该月是否有发放记录
            m_pays = [p for p in pays_to_date if p['结算月'] == m and p['业务员'] == person]
            if m_pays:
                amt = sum(p['金额'] for p in m_pays)
                types = ', '.join(p['类型'] for p in m_pays)
                WR(ws, rn, ['', f'{m}月: 已发', R(amt), types, ''])
            elif gm:
                # 有考核但未发
                # 检查是否在后续月被补发过（settle_month之前）
                bp_pays = [p for p in pays_to_date if p['对应考核月'] == m and p['业务员'] == person]
                if bp_pays:
                    amt = sum(p['金额'] for p in bp_pays)
                    sm = bp_pays[0]['结算月']
                    WR(ws, rn, ['', f'{m}月: 已发', R(amt), f'{sm}月补发', ''])
                else:
                    WR(ws, rn, ['', f'{m}月: 未发', 0, f'未达标(实际{R(gm["实际"],0)}<目标{R(gm["应考核"],0)})', ''])
            else:
                WR(ws, rn, ['', f'{m}月: 无记录', '', '', ''])
            rn += 1

        # 本月发放
        g_s = G.get(settle_month, {}).get((plate, person), {})
        if not isinstance(g_s, dict): g_s = {}
        gm_s = G.get(settle_month, {}).get((plate, person))
        plate_this_month = 0

        # 结转
        carry = g_s.get('结转', 0)
        if carry > 0:
            prev = settle_month - 1
            g_prev = G.get(prev, {}).get((plate, person))
            prev_excess = sum(r['多跑'] for r in g_prev['recs'] if r['是否达标'] == '达标') if g_prev else 0
            WR(ws, rn, ['', '结转', R(carry), f'{prev}月多跑{R(prev_excess,0)}≥{mkm}，结转(完整月奖金)', ''])
            plate_this_month += carry; rn += 1

        # 补发过去月份
        for prev_m in range(1, settle_month):
            bp_key = f'补发{prev_m}月'
            bp_amt = g_s.get(bp_key, 0)
            if bp_amt > 0:
                WR(ws, rn, ['', f'补发{prev_m}月', R(bp_amt), f'累计{R(cum_a,0)}≥{R(cum_t,0)}达标，补发{prev_m}月', ''])
                plate_this_month += bp_amt; rn += 1

        # 当月
        bonus = g_s.get('当月奖金', 0)
        if bonus > 0:
            excess = sum(r['多跑'] for r in gm_s['recs'] if r['是否达标'] == '达标') if gm_s else 0
            desc = '当月达标'
            if excess > 0 and mkm > 0 and int(excess // mkm) >= 1:
                desc += f'，多跑{R(excess,0)}≥{mkm}可结转'
            WR(ws, rn, ['', f'{settle_month}月当月', R(bonus), desc, ''])
            plate_this_month += bonus; rn += 1

        # 累计补发当月
        cum_bp = g_s.get(f'累计补发{settle_month}月', 0)
        if cum_bp > 0:
            WR(ws, rn, ['', f'累计补发{settle_month}月', R(cum_bp), f'累计{R(cum_a,0)}≥{R(cum_t,0)}达标，补发{settle_month}月', ''])
            plate_this_month += cum_bp; rn += 1

        # 无发放
        if plate_this_month == 0 and carry == 0:
            if gm_s:
                a_s = gm_s['实际']; t_s = gm_s['应考核']
                if gm_s.get('结转占位'):
                    WR(ws, rn, ['', '本月不发', 0, '结转占位，本月不另发', ''])
                else:
                    WR(ws, rn, ['', '本月不发', 0, f'未达标(实际{R(a_s,0)}<目标{R(t_s,0)})，累计也未达标', ''])
            else:
                WR(ws, rn, ['', '本月不发', 0, '本月无考核记录', ''])
            rn += 1

        # 本月合计 + 奖金池
        pool_str = f'已发{total_periods}期/共12期，剩余{12-total_periods}期'
        WR(ws, rn, ['', '本月合计', R(plate_this_month), '', pool_str])
        ws.cell(row=rn, column=2).font = Font(bold=True)
        ws.cell(row=rn, column=5).font = Font(italic=True)
        rn += 2  # 空行

    # 尾部
    ws.cell(row=rn,column=1,value=f'{person} {settle_month}月合计: {len(plates)}辆车, 发放 {R(person_total)}元').font=Font(bold=True,size=12)
    AW(ws)

# ============================================================
# 新增：车辆考核追踪sheet
# ============================================================

def write_vehicle_tracking_sheet(wb, settle_month, G, master_vehicles, vehicle_payments, vehicle_info, loss_data=None, plate_client=None):
    ws = wb.create_sheet('车辆考核追踪')
    from calc_engine import VEHICLE_TARGET_MAP, DAYS

    center_top = Alignment(horizontal='center', vertical='top', wrap_text=True)
    left_top = Alignment(vertical='top', wrap_text=True)
    green_font = Font(color='006100')
    green_fill = PatternFill(start_color='C6EFCE', end_color='C6EFCE', fill_type='solid')
    red_font = Font(color='9C0006')
    red_fill = PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid')
    grey_fill = PatternFill(start_color='F2F2F2', end_color='F2F2F2', fill_type='solid')
    blue_fill = PatternFill(start_color='DAEEF3', end_color='DAEEF3', fill_type='solid')
    gold_fill = PatternFill(start_color='FFF2CC', end_color='FFF2CC', fill_type='solid')

    # 表头：基本信息 + 业务员 + 每月(应考核/实际/达标) + 累计 + 发放 + 奖金池
    headers = ['车牌号','车架号','归属公司','车型','考核目标','月度奖励','业务员']
    info_cols = 6  # 前6列是车辆信息（需要合并）
    for m in range(1, settle_month+1):
        headers += [f'{m}月应考核', f'{m}月实际', f'{m}月达标']
    if settle_month >= 2:
        headers += ['累计应完成','累计实际','累计达标']
    if loss_data is not None:
        headers += ['客户名称','客户是否亏损','考核应发','最终发放','未发放原因']
    else:
        headers += ['本月发放金额','发放类型']
    headers += ['已发期数','已发金额','剩余期数']
    WH(ws, headers)
    ws.freeze_panes = 'H2'  # 冻结车辆信息+业务员列

    # 交替行底色
    stripe_a = PatternFill(start_color='FFFFFF', end_color='FFFFFF', fill_type='solid')  # 白
    stripe_b = PatternFill(start_color='DCE6F1', end_color='DCE6F1', fill_type='solid')  # 浅蓝
    vehicle_idx = 0

    rn = 2
    for mv in master_vehicles:
        plate = mv['车牌号']
        info = vehicle_info.get(plate, {})
        pays = vehicle_payments.get(plate, [])

        target_name = info.get('考核目标','')
        monthly_bonus = info.get('月度奖励',0)
        if not target_name:
            company = mv.get('归属公司','')
            vtype = mv.get('车型确定','')
            mapped = VEHICLE_TARGET_MAP.get((company, vtype))
            if mapped:
                target_name, _, monthly_bonus = mapped

        # 收集该车所有(业务员) - 跨月去重
        person_set = {}
        for m in range(1, settle_month+1):
            for k,g in G.get(m, {}).items():
                if k[0] == plate:
                    person_set[k[1]] = g['部门']
        persons = sorted(person_set.keys())
        if not persons:
            persons = ['']  # 无考核记录也占一行

        row_stripe = stripe_b if vehicle_idx % 2 == 1 else stripe_a
        start_rn = rn
        for pi, person in enumerate(persons):
            sd = person_set.get(person,'').replace('业务','') if person else ''
            person_label = f'{sd}-{person}' if person and sd else person

            # 车辆信息（只在第一行写，后面留空等合并）
            if pi == 0:
                row_base = [plate, mv.get('车架号',''), mv.get('归属公司',''),
                           mv.get('车型确定',''), target_name or '', monthly_bonus or '']
            else:
                row_base = ['','','','','','']

            row = row_base + [person_label]

            # 每月数据（按该业务员的group）
            cum_t = 0; cum_a = 0
            for m in range(1, settle_month+1):
                gm = G.get(m, {}).get((plate, person)) if person else None
                if gm:
                    # 逐条记录汇总（同人同月可能多条）
                    t_sum = gm['应考核']; a_sum = gm['实际']
                    cum_t += t_sum; cum_a += a_sum
                    # 每条记录的达标情况
                    rec_details = []
                    for rec in gm['recs']:
                        rq = rec['是否达标'] == '达标'
                        rec_details.append(f"{R(rec['实际行驶里程(km)'],0)}/{R(rec['应考核里程(km)'],0)}{'✓' if rq else '✗'}")
                    all_q = all(rec['是否达标'] == '达标' for rec in gm['recs'])
                    if len(gm['recs']) == 1:
                        detail = rec_details[0].split('✓')[0].split('✗')[0]  # 只取数字
                        row += [R(t_sum), R(a_sum), '✓' if all_q else '✗']
                    else:
                        # 多条：显示汇总，但单元格内注明各条
                        row += [R(t_sum), R(a_sum), '\n'.join(rec_details)]
                else:
                    row += ['', '', '']

            # 累计
            if settle_month >= 2:
                if cum_t > 0:
                    cum_q = cum_a >= cum_t
                    row += [R(cum_t), R(cum_a), '✓' if cum_q else '✗']
                else:
                    row += ['', '', '']
                    cum_q = False
            else:
                cum_q = False

            # 本月发放（该业务员的）
            tp = [p for p in pays if p['结算月'] == settle_month and p['业务员'] == person]
            考核应发 = sum(p['金额'] for p in tp) if tp else 0
            pay_types = ', '.join(p['类型'] for p in tp) if tp else ''

            if loss_data is not None:
                # 有亏损表：加客户名称、亏损状态、考核应发、最终发放、未发放原因
                client = (plate_client or {}).get(plate, '')
                loss_status = loss_data.get(client, '未匹配') if client else '未匹配'
                if loss_status == '是':
                    final_amt = 0
                    reason = '客户亏损不发放' if 考核应发 > 0 else ''
                elif loss_status == '未匹配':
                    final_amt = 0
                    reason = '未匹配亏损表' if 考核应发 > 0 else ''
                else:
                    final_amt = 考核应发
                    reason = ''
                row += [client, loss_status, R(考核应发), R(final_amt), reason]
            else:
                # 无亏损表：直接发放
                row += [R(考核应发), pay_types]

            # 奖金池（整车，只在第一行显示）
            if pi == 0:
                pays_to_date = [p for p in pays if p['结算月'] <= settle_month]
                tp_count = len(pays_to_date); tp_amt = sum(p['金额'] for p in pays_to_date)
                row += [f'{tp_count}/12', R(tp_amt) if tp_amt > 0 else 0, 12 - tp_count]
            else:
                row += ['', '', '']

            WR(ws, rn, row)

            # 美化：先刷底色（交替色），再叠加特殊色
            for ci in range(1, len(headers) + 1):
                ws.cell(row=rn, column=ci).fill = row_stripe

            # 车辆信息列灰底（覆盖条纹）
            for ci in range(1, info_cols + 1):
                ws.cell(row=rn, column=ci).fill = grey_fill if vehicle_idx % 2 == 0 else PatternFill(start_color='E8E8E8', end_color='E8E8E8', fill_type='solid')

            # 月度达标列着色
            for m in range(1, settle_month + 1):
                col_base = info_cols + 1 + (m - 1) * 3  # 业务员列后面
                qual_col = col_base + 3  # 达标列
                cell = ws.cell(row=rn, column=qual_col)
                cell.alignment = center_top
                val = cell.value
                if val and '✓' in str(val) and '✗' not in str(val):
                    cell.fill = green_fill; cell.font = green_font
                elif val and '✗' in str(val):
                    cell.fill = red_fill; cell.font = red_font

            # 累计达标着色
            if settle_month >= 2:
                cum_qual_col = info_cols + 1 + settle_month * 3 + 3  # 累计达标列
                cell = ws.cell(row=rn, column=cum_qual_col)
                if cell.value == '✓':
                    cell.fill = green_fill; cell.font = Font(bold=True, color='006100')
                elif cell.value == '✗':
                    cell.fill = red_fill; cell.font = Font(bold=True, color='9C0006')

            # 发放金底
            pay_col = info_cols + 1 + settle_month * 3 + (3 if settle_month >= 2 else 0) + 1
            if tp:
                ws.cell(row=rn, column=pay_col).fill = gold_fill

            # 奖金池蓝底
            if pi == 0 and tp_count > 0:
                pool_col = pay_col + 2
                ws.cell(row=rn, column=pool_col).fill = blue_fill
                ws.cell(row=rn, column=pool_col).font = Font(bold=True)

            rn += 1

        # 合并车辆信息列（如果多人）
        if len(persons) > 1:
            for ci in range(1, info_cols + 1):
                ws.merge_cells(start_row=start_rn, start_column=ci,
                              end_row=start_rn + len(persons) - 1, end_column=ci)
                ws.cell(row=start_rn, column=ci).alignment = Alignment(vertical='center', wrap_text=True)
            # 奖金池列也合并
            for offset in [2, 3, 4]:  # 已发期数/已发金额/剩余期数
                pool_col = pay_col + offset
                ws.merge_cells(start_row=start_rn, start_column=pool_col,
                              end_row=start_rn + len(persons) - 1, end_column=pool_col)

        vehicle_idx += 1

    # 列宽
    # 隐藏BCD列（车架号/归属公司/车型）
    for cl in ['B','C','D']:
        ws.column_dimensions[cl].hidden = True
    col_widths = {'A':12,'B':18,'C':18,'D':10,'E':18,'F':8,'G':14}
    for cl, w in col_widths.items():
        ws.column_dimensions[cl].width = w
    # 月度列
    start = ord('H')
    for m in range(settle_month):
        for i in range(3):
            cl = chr(start + m*3 + i)
            if cl <= 'Z': ws.column_dimensions[cl].width = 12
    # 剩余列
    rem = start + settle_month * 3
    for i in range(10):
        cl = chr(rem + i)
        if cl <= 'Z': ws.column_dimensions[cl].width = 14
