#!/usr/bin/env python3
"""Запускает долгий рендер, пишет журнал и останавливает только реально зависший процесс."""
from __future__ import annotations
import argparse, os, shlex, subprocess, sys, time
from pathlib import Path

def main():
    ap=argparse.ArgumentParser(); ap.add_argument('--output',required=True); ap.add_argument('--log',default='render.log'); ap.add_argument('--stall-seconds',type=int,default=240); ap.add_argument('--total-timeout',type=int,default=7200); ap.add_argument('command',nargs=argparse.REMAINDER); args=ap.parse_args()
    cmd=args.command[1:] if args.command and args.command[0]=='--' else args.command
    if not cmd: raise SystemExit('После -- передайте команду рендера')
    out=Path(args.output); log=Path(args.log); log.parent.mkdir(parents=True,exist_ok=True); out.parent.mkdir(parents=True,exist_ok=True)
    start=time.time(); last_change=start; last_size=-1
    with log.open('w',encoding='utf-8',errors='replace') as lf:
        p=subprocess.Popen(cmd,stdout=lf,stderr=subprocess.STDOUT,text=True)
        while p.poll() is None:
            time.sleep(5)
            size=out.stat().st_size if out.exists() else 0
            if size!=last_size or log.stat().st_size>0 and log.stat().st_mtime>last_change:
                last_size=size; last_change=time.time()
            if time.time()-last_change>args.stall_seconds:
                p.terminate(); time.sleep(5)
                if p.poll() is None: p.kill()
                raise SystemExit(f'Рендер не менялся {args.stall_seconds} секунд. Процесс остановлен. См. {log}')
            if time.time()-start>args.total_timeout:
                p.terminate(); raise SystemExit('Превышен общий лимит рендера')
        if p.returncode!=0: raise SystemExit(f'Рендер завершился с кодом {p.returncode}. См. {log}')
    print(f'Успех: {out} ({out.stat().st_size} байт)')
if __name__=='__main__': main()
