#!/usr/bin/env python3
"""Fixture-specific chart/cache check plus faults on in-memory copies of a PPTX."""
import argparse,hashlib,json,math,platform,posixpath,time
from io import BytesIO
from pathlib import Path
from zipfile import ZipFile,ZIP_DEFLATED
from xml.etree import ElementTree as ET
import openpyxl
C='http://schemas.openxmlformats.org/drawingml/2006/chart';R='http://schemas.openxmlformats.org/officeDocument/2006/relationships';NS={'c':C}
def points(node):
    return [p.find('c:v',NS).text for p in sorted(node.findall('c:pt',NS),key=lambda p:int(p.get('idx')))]
def package(data):
    with ZipFile(BytesIO(data)) as z:return {n:z.read(n) for n in z.namelist()}
def packed(parts):
    out=BytesIO()
    with ZipFile(out,'w',ZIP_DEFLATED) as z:
        for name,data in parts.items():z.writestr(name,data)
    return out.getvalue()
def check(data):
    parts=package(data);mismatches=[];checked=0;charts=0
    for name in sorted(parts):
        if not (name.startswith('ppt/charts/chart') and name.endswith('.xml')):continue
        charts+=1;chart=ET.fromstring(parts[name]);external=chart.find('c:externalData',NS)
        assert external is not None,'Fixture requires embedded chart data'
        relpath=posixpath.join(posixpath.dirname(name),'_rels',posixpath.basename(name)+'.rels')
        rels=ET.fromstring(parts[relpath]);rel=next(r for r in rels if r.get('Id')==external.get('{'+R+'}id'))
        assert rel.get('TargetMode')!='External'
        target=posixpath.normpath(posixpath.join(posixpath.dirname(name),rel.get('Target')))
        workbook=openpyxl.load_workbook(BytesIO(parts[target]),read_only=True,data_only=True)
        try:
            sheet=workbook.active;series=chart.findall('.//c:ser',NS);categories=points(series[0].find('c:cat/c:strLit',NS))
            expected_categories=[str(sheet.cell(row,1).value) for row in range(2,2+len(categories))]
            for idx,(cached,embedded) in enumerate(zip(categories,expected_categories)):
                checked+=1
                if cached!=embedded:mismatches.append(dict(chart=name,kind='category',index=idx,cached=cached,embedded=embedded))
            for idx,ser in enumerate(series):
                title=points(ser.find('c:tx/c:strRef/c:strCache',NS))[0];checked+=1
                if title!=sheet.cell(1,idx+2).value:mismatches.append(dict(chart=name,kind='title',series=idx))
                values=points(ser.find('c:val/c:numLit',NS));assert len(values)==len(categories)
                for j,value in enumerate(values):
                    embedded=sheet.cell(j+2,idx+2).value;cached=float(value);checked+=1
                    if not math.isclose(cached,float(embedded),rel_tol=1e-10,abs_tol=1e-8):mismatches.append(dict(chart=name,kind='value',series=idx,index=j,cached=cached,embedded=embedded))
        finally:workbook.close()
    return dict(status='PASS' if not mismatches else 'FAIL',charts=charts,items_checked=checked,mismatches=mismatches)
if __name__=='__main__':
    p=argparse.ArgumentParser();p.add_argument('pptx',type=Path);p.add_argument('--report',type=Path,required=True);a=p.parse_args();original=a.pptx.read_bytes();cases=[('original',original)]
    parts=package(original);name='ppt/charts/chart1.xml';chart=ET.fromstring(parts[name]);value=chart.find('.//c:ser/c:val/c:numLit/c:pt[@idx="11"]/c:v',NS);value.text=str(float(value.text)+1);parts[name]=ET.tostring(chart,encoding='utf-8',xml_declaration=True);cases.append(('chart_value_only_plus_one',packed(parts)))
    parts=package(original);name='ppt/embeddings/Microsoft_Excel_Worksheet.xlsx';wb=openpyxl.load_workbook(BytesIO(parts[name]));wb.active['B13']=float(wb.active['B13'].value)+1;out=BytesIO();wb.save(out);wb.close();parts[name]=out.getvalue();cases.append(('embedded_value_only_plus_one',packed(parts)))
    results=[]
    for label,data in cases:
        t=time.perf_counter();r=check(data);r.update(scenario=label,local_seconds=round(time.perf_counter()-t,6));results.append(r)
    assert results[0]['status']=='PASS' and results[0]['charts']==3
    assert all(r['status']=='FAIL' and len(r['mismatches'])==1 for r in results[1:])
    assert a.pptx.read_bytes()==original
    report=dict(experiment='native-deck-chart-consistency',source_sha256=hashlib.sha256(original).hexdigest(),python=platform.python_version(),openpyxl=openpyxl.__version__,results=results,
                limits='Fixture-specific reader: category strLit and value numLit chart data, one row per month, series in adjacent embedded Sheet1 columns. Unsupported representations are not certified. Local package checks and in-memory faults only; no new PowerPoint execution or claim about how a modified deck renders. No task bill measured.')
    a.report.write_text(json.dumps(report,indent=2)+'\n');print(json.dumps(report,indent=2))
