#!/usr/bin/env python3
"""危大方案看板数据工作簿 v5 — 双数据源(OA登记+公司认定) + GROUPBY/FILTER动态公式"""
import pandas as pd
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter

BASE = "/mnt/y/Openclaw_Hub/03.资源/实施项目 wiki/dashboard/data/2026-06-08"
CERT_DIR = "/mnt/y/Openclaw_Hub/03.资源/实施项目 wiki/dashboard/data/认定数据/2026"  # 年度固定目录·一年一次
OUT = f"{BASE}/cleaned/危大方案看板数据工作簿.xlsx"
REPORT_DATE = "2026-06-08"
REF = "'有效≥2026'"  # OA公式引用
CREF = "'认定数据'"  # 认定公式引用

# ════ 数据源1: OA登记（methods_cleaned.csv） ════
df = pd.read_csv(f"{BASE}/cleaned/methods_cleaned.csv")
SRC_COLS = list(df.columns[:24])
valid_all = df[df['是否有效登记'] == True].copy()
valid_2026 = valid_all[valid_all['开工年份'] >= 2026].copy()
m = valid_2026
tot = len(m); gen = (m['是否超一定规模']!='是').sum(); sup = tot-gen
completed = m['是否完成审批'].sum(); unfinished = tot-completed
projects = m['项目名称'].nunique(); countries = m['所属国别'].value_counts().to_dict()
warn_df = m[m['预警信号']!='none'].sort_values('分部分项工程计划开工日期')
warn_total = len(warn_df); orange = (warn_df['预警信号']=='orange').sum(); yellow = warn_total-orange
print(f"OA登记: {tot}项(一般{gen}/超规{sup}) 完成{completed} 预警{orange}橙{yellow}黄")

# ════ 数据源2: 公司认定（certified_schemes_detail.csv） ════
cert_raw = pd.read_csv(f"{CERT_DIR}/certified_schemes_detail.csv")
cert_raw['计划开工日期_p'] = pd.to_datetime(cert_raw['计划开工日期'].astype(str).str.replace('.','-'), errors='coerce')
cert_valid = cert_raw[cert_raw['计划开工日期_p'].dt.year >= 2026].copy()
cert_tot = len(cert_valid)
cert_sup = (cert_valid['是否超一定规模']=='是').sum(); cert_gen = cert_tot-cert_sup
cert_comp = pd.read_csv(f"{CERT_DIR}/certified_schemes.csv")
# 表2: I II Ⅲ类技术方案
tech_raw = pd.read_csv(f"{CERT_DIR}/certified_tech_schemes_detail.csv")
tech_raw['计划开工日期_p'] = pd.to_datetime(tech_raw['计划开工日期'].astype(str).str.replace('.','-'), errors='coerce')
tech_valid = tech_raw[tech_raw['计划开工日期_p'].dt.year >= 2026].copy()
tech_tot = len(tech_valid)
print(f"公司认定: 表1危大{cert_tot}项({cert_gen}一般/{cert_sup}超规) + 表2技术{tech_tot}项 = {cert_tot+tech_tot}总计")

# ════ 样式 ════
HDR_F=Font(name='微软雅黑',bold=True,size=10,color='FFFFFF'); HDR_BG=PatternFill('solid',fgColor='1A3A5C')
TITLE_F=Font(name='微软雅黑',bold=True,size=14,color='1A3A5C'); DATA_F=Font(name='微软雅黑',size=10)
BOLD_F=Font(name='微软雅黑',bold=True,size=10); GRAY_F=Font(name='微软雅黑',size=9,color='8899AA')
GREEN_F=Font(name='微软雅黑',bold=True,size=10,color='2E7D32'); RED_F=Font(name='微软雅黑',bold=True,size=10,color='D94E34')
BLUE_F=Font(name='微软雅黑',bold=True,size=10,color='1A3A5C'); ORANGE_F=Font(name='微软雅黑',bold=True,size=10,color='E65100')
FORMULA_F=Font(name='Consolas',size=10,color='1A3A5C')
WARN_BG=PatternFill('solid',fgColor='FFF3E0'); INFO_BG=PatternFill('solid',fgColor='F0F4FA')
BORDER=Border(left=Side('thin','DBE2EA'),right=Side('thin','DBE2EA'),top=Side('thin','DBE2EA'),bottom=Side('thin','DBE2EA'))
CENTER=Alignment(horizontal='center',vertical='center',wrap_text=True)
GOLD_BD=Border(bottom=Side(style='medium',color='C8962E'))

def hdr_row(ws,r,cols):
    for i,h in enumerate(cols):
        c=ws.cell(r,i+1,h); c.font=HDR_F; c.fill=HDR_BG; c.border=BORDER; c.alignment=CENTER

def write_data_sheet(ws,df_out,title,cols):
    ncol=len(cols)
    ws.merge_cells(start_row=1,start_column=1,end_row=1,end_column=ncol)
    ws.cell(1,1,title).font=TITLE_F; ws.cell(1,1).border=GOLD_BD
    hdr_row(ws,3,cols)
    for ri,(_,row) in enumerate(df_out.iterrows()):
        rr=ri+4
        for ci,col in enumerate(cols):
            v=row.get(col,'')
            if pd.isna(v): v=''
            elif isinstance(v,(pd.Timestamp,)): v=str(v)[:10]
            elif isinstance(v,(float,)) and v==int(v): v=int(v)
            ws.cell(rr,ci+1,v).font=DATA_F; ws.cell(rr,ci+1,v).border=BORDER
    ws.auto_filter.ref=f'A3:{get_column_letter(ncol)}{len(df_out)+3}'
    ws.freeze_panes='A4'
    for i,col in enumerate(cols):
        ws.column_dimensions[get_column_letter(i+1)].width=max(10,min(40,len(str(col))*2.2))

def write_formula_sheet(ws,title,subtitle,formulas,col_widths):
    ws.merge_cells(start_row=1,start_column=1,end_row=1,end_column=4)
    ws.cell(1,1,title).font=TITLE_F; ws.cell(1,1).border=GOLD_BD
    if subtitle:
        ws.merge_cells(start_row=2,start_column=1,end_row=2,end_column=4)
        ws.cell(2,1,subtitle).font=Font(name='微软雅黑',size=9,color='8899AA')
    for col_letter,row_num,formula,label in formulas:
        cell=ws.cell(row_num,ord(col_letter)-64,formula); cell.font=FORMULA_F; cell.border=BORDER
        if label:
            ws.cell(row_num,ord(col_letter)-63,label).font=GRAY_F
    for col_letter,w in col_widths:
        ws.column_dimensions[col_letter].width=w
    ws.merge_cells(start_row=12,start_column=1,end_row=12,end_column=4)
    ws.cell(12,1,'💡 源数据更新后公式自动刷新（WPS新版/Excel 365）').font=GRAY_F; ws.cell(12,1).fill=INFO_BG

wb = Workbook()

# ════════ S1: OA清洗后数据 ════════
s1=wb.active; s1.title='清洗后数据'
write_data_sheet(s1,valid_all.reset_index(drop=True),
    f'OA登记·清洗后数据（有效登记·全部年份·{len(valid_all)}行）',
    SRC_COLS+['方案状态_clean','是否完成审批','是否有效登记','开工年份','开工月份','预警信号'])

# ════════ S2: OA有效≥2026 ════════
s2=wb.create_sheet('有效≥2026')
write_data_sheet(s2,valid_2026.reset_index(drop=True),
    f'OA登记·有效≥2026年开工（{len(valid_2026)}行）',
    SRC_COLS+['方案状态_clean','是否完成审批','是否有效登记','开工年份','开工月份','预警信号'])

# ════════ S3: 认定数据 ════════
s3=wb.create_sheet('认定数据')
CERT_COLS=['所属区域','所属国别','项目名称','方案名称','编制单位','工程类别','分部工程类别','是否超一定规模','计划开工日期']
write_data_sheet(s3,cert_valid.reset_index(drop=True),
    f'2026年度公司认定危大方案明细（中港科技便〔2026〕6号·{cert_tot}项）',CERT_COLS)

# ════════ S4: 认定vsOA ════════
s4=wb.create_sheet('认定vsOA')
COMP_COLS=['项目名称','认定_危大方案总数','认定_超规数','所属国别','平台_方案总数','平台_超规数','差额','匹配状态']
ncol_c=len(COMP_COLS)
s4.merge_cells(start_row=1,start_column=1,end_row=1,end_column=ncol_c)
s4.cell(1,1,f'认定 vs OA登记 项目级对比（{REPORT_DATE}）').font=TITLE_F; s4.cell(1,1).border=GOLD_BD
hdr_row(s4,3,COMP_COLS)
for ri,(_,row) in enumerate(cert_comp.iterrows()):
    for ci,col in enumerate(COMP_COLS):
        v=row[col]
        if pd.isna(v): v=''
        cell=s4.cell(ri+4,ci+1,v); cell.font=DATA_F; cell.border=BORDER
        if col=='差额' and isinstance(v,(int,float)) and v!=0:
            cell.font=RED_F if v<0 else GREEN_F
        if col=='匹配状态': cell.font=GREEN_F if '✅' in str(v) else DATA_F
s4.auto_filter.ref=f'A3:{get_column_letter(ncol_c)}{len(cert_comp)+3}'
for i,col in enumerate(COMP_COLS):
    s4.column_dimensions[get_column_letter(i+1)].width=max(14,min(45,len(str(col))*2.5))

# ════════ S4b: 认定技术方案（表2） ════════
s4b=wb.create_sheet('认定技术方案')
TECH_COLS=['所属国别','项目名称','方案名称','编制单位','工程类别','方案等级','工程特点/说明','计划开工日期']
write_data_sheet(s4b,tech_valid.reset_index(drop=True),
    f'2026年度公司认定技术方案明细（ⅠⅡⅢ类·中港科技便〔2026〕6号·{tech_tot}项）',TECH_COLS)

# ── 公式-技术方案分类 ──
s4bf=wb.create_sheet('公式-技术方案分类')
TREF = "'认定技术方案'"
write_formula_sheet(s4bf,f'认定技术方案等级分布（GROUPBY·{tech_tot}项）',
    f'GROUPBY({TREF}!F3:F200,{TREF}!C3:C200,COUNTA,3,0)',
    [('A',4,f'=GROUPBY({TREF}!F3:F200,{TREF}!C3:C200,COUNTA,3,0)','')],[('A',20),('B',12)])

# ════════ S5-S8: 动态公式 ════════

# ── S5: 公式-年度认定 ──
s5=wb.create_sheet('公式-年度认定')
write_formula_sheet(s5,f'OA年度认定（≥2026开工）',
    f'GROUPBY({REF}!K3:K200,{REF}!A3:A200,COUNTA,3,0)',
    [('A',4,f'=GROUPBY({REF}!K3:K200,{REF}!A3:A200,COUNTA,3,0)','')],[('A',18),('B',12)])

# ── S6: 公式-国别分布 ──
s6=wb.create_sheet('公式-国别分布')
write_formula_sheet(s6,f'OA国别×分类（自动排序）',
    f'GROUPBY({REF}!C3:C200,{REF}!A3:A200,COUNTA,3,0,-2)',
    [('A',4,f'=GROUPBY({REF}!C3:C200,{REF}!A3:A200,COUNTA,3,0,-2)','')],[('A',30),('B',12)])

# ── S7: 公式-审批进度 ──
s7=wb.create_sheet('公式-审批进度')
write_formula_sheet(s7,f'OA审批进度 & 预警',
    f'引用 {REF}!Z:Z + AD:AD',
    [('A',4,'方案总数',''),('B',4,f'=COUNTA({REF}!A4:A200)',''),
     ('A',5,'已完成审批',''),('B',5,f'=COUNTIF({REF}!Z4:Z200,TRUE)',''),
     ('A',6,'未完成审批',''),('B',6,f'=COUNTIF({REF}!Z4:Z200,FALSE)',''),
     ('A',7,'橙色预警',''),('B',7,f'=COUNTIF({REF}!AD4:AD200,"orange")',''),
     ('A',8,'黄色预警',''),('B',8,f'=COUNTIF({REF}!AD4:AD200,"yellow")',''),
     ('A',9,'预警合计',''),('B',9,'=B7+B8','')],[('A',20),('B',14)])

# ── S8: 公式-预警明细 ──
s8=wb.create_sheet('公式-预警明细')
write_formula_sheet(s8,f'OA预警明细（FILTER）',
    f'FILTER({REF}!A3:AD200,{REF}!AD3:AD200<>"none","无预警")',
    [('A',4,f'=FILTER({REF}!A3:AD200,{REF}!AD3:AD200<>"none","🎉 无预警项")','')],[('A',22)])

# ── S9: 公式-认定分类 ──
s9=wb.create_sheet('公式-认定分类')
write_formula_sheet(s9,f'公司认定方案分类（GROUPBY·{cert_tot}项）',
    f'GROUPBY({CREF}!H3:H200,{CREF}!D3:D200,COUNTA,3,0)',
    [('A',4,f'=GROUPBY({CREF}!H3:H200,{CREF}!D3:D200,COUNTA,3,0)','')],[('A',20),('B',12)])

# ════════ S10-S13: 静态汇总表（可交叉验证） ════════

# ── S10: 年度认定汇总 ──
s10=wb.create_sheet('年度认定汇总')
s10.merge_cells('A1:E1'); s10.cell(1,1,f'OA年度认定（≥2026·静态）').font=TITLE_F; s10.cell(1,1).border=GOLD_BD
hdr_row(s10,3,['分类','方案数','项目数','占比','备注'])
for r,(lab,val,proj,pct,note) in enumerate([
    ('一般类',gen,valid_2026[valid_2026['是否超一定规模']!='是']['项目名称'].nunique(),f'{gen/tot*100:.0f}%','非超一定规模'),
    ('超规类',sup,valid_2026[valid_2026['是否超一定规模']=='是']['项目名称'].nunique(),f'{sup/tot*100:.0f}%','超一定规模'),
    ('合计',tot,projects,'100%',f'涵盖{len(countries)}国')]):
    fmts=[BOLD_F if '合计' in lab else DATA_F]*5
    for c,(v,f) in enumerate(zip([lab,val,proj,pct,note],fmts)):
        cell=s10.cell(r+4,c+1,v); cell.font=f; cell.border=BORDER; cell.alignment=CENTER
for w,col in zip([12,10,10,10,20],'ABCDE'): s10.column_dimensions[col].width=w

# ── S11: 国别×分类 ──
s11=wb.create_sheet('国别×分类')
s11.merge_cells('A1:D1'); s11.cell(1,1,'OA国别×分类·静态').font=TITLE_F; s11.cell(1,1).border=GOLD_BD
ct=m.groupby(['所属国别','是否超一定规模']).size().unstack(fill_value=0)
ct.columns=['一般类' if c=='否' else '超规类' for c in ct.columns]; ct['合计']=ct.sum(1); ct.loc['合计']=ct.sum()
hdr_row(s11,3,['国别']+list(ct.columns))
for r,(idx,row) in enumerate(ct.iterrows()):
    for c,v in enumerate([idx]+[int(x) for x in row]):
        cell=s11.cell(r+4,c+1,v); cell.font=BOLD_F if '合计' in str(idx) else DATA_F; cell.border=BORDER; cell.alignment=CENTER
s11.column_dimensions['A'].width=25

# ── S12: 审批进度 ──
s12=wb.create_sheet('审批进度')
s12.merge_cells('A1:D1'); s12.cell(1,1,f'OA审批进度·静态（{REPORT_DATE}）').font=TITLE_F; s12.cell(1,1).border=GOLD_BD
hdr_row(s12,3,['指标','数值','占比','备注'])
for r,(lab,val,pct,note,fmts) in enumerate([
    ('方案总数',tot,'100%','≥2026年开工',[BLUE_F]*3+[GRAY_F]),
    ('已完成审批',int(completed),f'{completed/tot*100:.0f}%','含"已完成"',[GREEN_F]*3+[GRAY_F]),
    ('未完成审批',int(unfinished),f'{unfinished/tot*100:.0f}%','审批中+未审批',[DATA_F]*3+[GRAY_F]),
    ('🟠 橙色预警',int(orange),f'{orange/tot*100:.0f}%','≤30天',[ORANGE_F]*3+[GRAY_F]),
    ('🟡 黄色预警',int(yellow),f'{yellow/tot*100:.0f}%','≤45天',[Font(name='微软雅黑',bold=True,size=10,color='F9A825')]*3+[GRAY_F]),
    ('预警合计',int(warn_total),f'{warn_total/tot*100:.0f}%',f'🟠{orange}+🟡{yellow}',[RED_F]*3+[GRAY_F])]):
    for c,(v,f) in enumerate(zip([lab,val,pct,note],fmts)):
        cell=s12.cell(r+4,c+1,v); cell.font=f; cell.border=BORDER; cell.alignment=CENTER
for w,col in zip([18,10,10,35],'ABCD'): s12.column_dimensions[col].width=w

# ── S13: 预警明细 ──
s13=wb.create_sheet('预警明细')
s13.merge_cells('A1:H1'); s13.cell(1,1,f'OA预警明细·静态（共{warn_total}项）').font=TITLE_F; s13.cell(1,1).border=GOLD_BD
hdr_row(s13,3,['信号','距开工','项目名称','方案名称','方案状态','计划开工','超规/一般','国别'])
today=pd.Timestamp(REPORT_DATE)
for r,(_,row) in enumerate(warn_df.iterrows()):
    days=(pd.to_datetime(row['分部分项工程计划开工日期'])-today).days
    vals=[{'orange':'🟠','yellow':'🟡','red':'🔴'}.get(row['预警信号'],''),f'{int(days)}天',
          row['项目名称'],row['方案名称'],
          row['方案状态_clean'] if pd.notna(row.get('方案状态_clean')) else row['方案状态'],
          str(row['分部分项工程计划开工日期'])[:10],
          '超规类' if row['是否超一定规模']=='是' else '一般类',row['所属国别']]
    for c,v in enumerate(vals):
        cell=s13.cell(r+4,c+1,v); cell.font=RED_F if c==1 and days<=3 else DATA_F; cell.border=BORDER; cell.fill=WARN_BG
s13.auto_filter.ref=f'A3:H{warn_total+3}'
for w,col in zip([6,8,40,35,18,12,10,20],'ABCDEFGH'): s13.column_dimensions[col].width=w

wb.save(OUT)
print(f"\n✅ {OUT}")
print(f"   S1-S2  OA登记: {len(valid_all)}全量 + {len(valid_2026)}≥2026")
print(f"   S3     认定危大方案(表1): {cert_tot}行({cert_gen}一般+{cert_sup}超规)")
print(f"   S4     认定vsOA: {len(cert_comp)}项目")
print(f"   S4b    认定技术方案(表2): {tech_tot}行")
print(f"   S5-S10 GROUPBY/FILTER 动态公式(含表1+表2)")
print(f"   S11-S14 静态汇总表(交叉验证)")
