# -*- coding: utf-8 -*-
"""原创离线合成样例；不连接模型、不读取账户。输出位于脚本旁。
已有输入保留，修改输入后可以重跑。失败边界由 --negative 单独演示。
"""
from pathlib import Path
import sys, json, csv, math, io, hashlib, html, base64, re
sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')
BASE = Path(__file__).resolve().parent
NEG = '--negative' in sys.argv
def write(name, value):
    p=BASE/name; p.parent.mkdir(parents=True,exist_ok=True)
    if isinstance(value,bytes): p.write_bytes(value)
    else: p.write_text(value,encoding='utf-8',newline='')
def seed(name,value):
    if not (BASE/name).exists(): write(name,value)
def jwrite(name,value): write(name,json.dumps(value,ensure_ascii=False,indent=2))
def jseed(name,value):
    if not (BASE/name).exists(): jwrite(name,value)
def load(name): return json.loads((BASE/name).read_text(encoding='utf-8'))
def table(name,heads,rows):
    f=io.StringIO(newline='');w=csv.writer(f);w.writerow(heads);w.writerows(rows);write(name,f.getvalue())
def page(name,title,body):
    write(name,'<!doctype html><html lang="zh-CN"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>'+html.escape(title)+'</title><style>body{max-width:1000px;margin:2rem auto;padding:0 1rem;font:17px/1.7 system-ui}table{border-collapse:collapse}td,th{border:1px solid #aaa;padding:.5rem}pre{white-space:pre-wrap;overflow-wrap:anywhere}img,svg{max-width:100%;height:auto}a{color:#125caa}</style><h1>'+html.escape(title)+'</h1>'+body+'</html>')
def emit(data): print(json.dumps(data,ensure_ascii=False))

from datetime import datetime,timezone
seed('local-source.txt','原创合成媒体源定位演示；不是实际视频。\n');sha=hashlib.sha256((BASE/'local-source.txt').read_bytes()).hexdigest()
jseed('file-manifest.json',{'local_path':'local-source.txt','sha256':sha,'remote_records':[{'name':'files/old','uri':'https://generativelanguage.googleapis.com/v1beta/files/old','state':'ACTIVE','expirationTime':'2026-10-23T12:00:00Z'},{'name':'files/current','uri':'https://generativelanguage.googleapis.com/v1beta/files/current','state':'ACTIVE','expirationTime':'2026-10-25T12:00:00Z'},{'name':'files/processing','uri':'','state':'PROCESSING'},{'name':'files/failed','uri':'','state':'FAILED'},{'name':'files/unknown','uri':'','state':'FUTURE_STATE'},{'name':'files/no-expiry','uri':'https://generativelanguage.googleapis.com/v1beta/files/no-expiry','state':'ACTIVE'}]})
now=datetime(2026,10,24,tzinfo=timezone.utc);data=load('file-manifest.json');rows=[]
if NEG:data['local_path']='missing-source.txt'
local=BASE/data['local_path']
if local.exists() and hashlib.sha256(local.read_bytes()).hexdigest()!=data['sha256']:raise ValueError('本地源摘要变化，不能复用旧远端引用；请作为新源建立上传记录')
for r in data['remote_records']:
    expiration=r.get('expirationTime');expired=expiration and datetime.fromisoformat(expiration.replace('Z','+00:00'))<=now
    if expired:
        if not (BASE/data['local_path']).exists():raise FileNotFoundError('源文件丢失，不能完成过期重传：'+data['local_path'])
        action='reupload_from_local'
    elif r['state']=='PROCESSING':action='wait_and_get_status'
    elif r['state']=='FAILED':action='inspect_error'
    elif r['state']=='ACTIVE' and expiration and r.get('uri'):action='reuse_if_fresh_status'
    elif r['state']=='ACTIVE':action='refresh_missing_metadata'
    else:action='unknown_preserve_and_inspect'
    rows.append([r['name'],r['state'],expiration,action])
table('lifecycle.csv',['name','state','expirationTime','action'],rows)
emit({'actions':rows,'local_source_retained':(BASE/data['local_path']).exists(),'clock':now.isoformat()})
