"""Public synthetic ZIP samples: keep duplicate directory entries intact."""
from pathlib import Path
import base64, hashlib, io, json, platform, struct, warnings, zipfile, zlib

OUT=Path(__file__).resolve().parent/'generated'
OUT.mkdir(parents=True,exist_ok=True)
NAME='note.txt'
FIRST=b'FIRST: red sample.\n'
SECOND=b'SECOND: blue sample.\n'

def build(payloads):
    buffer=io.BytesIO()
    with warnings.catch_warnings(record=True) as caught:
        warnings.simplefilter('always')
        with zipfile.ZipFile(buffer,'w',compression=zipfile.ZIP_STORED) as archive:
            for content in payloads:
                info=zipfile.ZipInfo(NAME,date_time=(1980,1,1,0,0,0))
                info.compress_type=zipfile.ZIP_STORED
                info.create_system=0
                info.external_attr=0x20
                archive.writestr(info,content)
    return buffer.getvalue(),[str(w.message) for w in caught]

def inspect(data):
    # Independent central-directory traversal; no filename-keyed dictionary.
    end=data.rfind(b'PK\x05\x06')
    sig,disk,cd_disk,disk_count,count,cd_size,cd_start,comment_size=struct.unpack_from('<4s4H2IH',data,end)
    assert disk==cd_disk==0 and disk_count==count
    assert end+22+comment_size==len(data) and cd_start+cd_size==end
    pos=cd_start;rows=[]
    for index in range(count):
        assert data[pos:pos+4]==b'PK\x01\x02'
        flags,method=struct.unpack_from('<HH',data,pos+8)
        crc,compressed,size=struct.unpack_from('<III',data,pos+16)
        name_size,extra_size,note_size=struct.unpack_from('<HHH',data,pos+28)
        local=struct.unpack_from('<I',data,pos+42)[0]
        name=data[pos+46:pos+46+name_size].decode('ascii')
        assert flags==0 and method==0 and data[local:local+4]==b'PK\x03\x04'
        local_crc,local_compressed,local_size=struct.unpack_from('<III',data,local+14)
        local_name_size,local_extra_size=struct.unpack_from('<HH',data,local+26)
        assert data[local+30:local+30+local_name_size].decode('ascii')==name
        payload_start=local+30+local_name_size+local_extra_size
        payload=data[payload_start:payload_start+compressed]
        assert local_crc==crc==zlib.crc32(payload)
        assert local_compressed==compressed==local_size==size==len(payload)
        rows.append(dict(index=index,name=name,central_offset=pos,local_offset=local,
            payload_start=payload_start,compressed_bytes=compressed,output_bytes=size,
            crc32=f'{crc:08x}',text=payload.decode('ascii')))
        pos+=46+name_size+extra_size+note_size
    assert pos==cd_start+cd_size
    accounting=dict(payload_bytes=sum(r['output_bytes'] for r in rows),
        local_header_and_name_bytes=sum(r['payload_start']-r['local_offset'] for r in rows),
        central_directory_bytes=cd_size,end_record_bytes=22+comment_size)
    assert sum(accounting.values())==len(data)
    return rows,accounting

def main():
    report=dict(python=platform.python_version(),compression='ZIP_STORED',cases={})
    for name,payloads in [('single',[FIRST]),('duplicates',[FIRST,SECOND]),('reversed',[SECOND,FIRST])]:
        data,warning=build(payloads)
        encoded=base64.b64encode(data)
        (OUT/(name+'.zip')).write_bytes(data)
        (OUT/(name+'.b64.txt')).write_bytes(encoded)
        decoded=base64.b64decode(encoded,validate=True)
        assert decoded==data
        rows,accounting=inspect(decoded)
        with zipfile.ZipFile(io.BytesIO(decoded)) as archive:
            infos=archive.infolist()
            for index,info in enumerate(infos):
                actual=archive.read(info)
                assert actual==payloads[index] and actual.decode('ascii')==rows[index]['text']
                assert info.header_offset==rows[index]['local_offset']
                (OUT/f'{name}-index-{index}.txt').write_bytes(actual)
            by_name=archive.read(NAME)
            (OUT/(name+'-by-name.txt')).write_bytes(by_name)
            bad=archive.testzip()
            assert bad is None
        report['cases'][name]=dict(archive_bytes=len(data),base64_characters=len(encoded),
            sha256=hashlib.sha256(data).hexdigest(),roundtrip_equal=True,
            directory_entries=len(rows),distinct_names=len(set(r['name'] for r in rows)),
            payload_sum=sum(r['output_bytes'] for r in rows),by_name_bytes=len(by_name),
            by_name_text=by_name.decode('ascii'),testzip_result=bad,
            creation_warnings=warning,accounting=accounting,entries=rows)
    (OUT/'measurements.json').write_text(json.dumps(report,indent=2)+'\n',encoding='utf-8')
    (OUT/'directory-index.json').write_text(json.dumps(report['cases']['duplicates']['entries'],indent=2)+'\n',encoding='utf-8')
    print(json.dumps(report,indent=2))

if __name__=='__main__':main()
