import hashlib
import json
import os
import time
import psycopg2
import redis
from psycopg2.extras import RealDictCursor


def events(since):
    with psycopg2.connect(os.environ['DATABASE_URL'],connect_timeout=3,
                         options='-c statement_timeout=2500 -c default_transaction_read_only=on') as conn:
        with conn.cursor(cursor_factory=RealDictCursor) as cur:
            cur.execute('''SELECT event_id, payload, relative_path, artifact_state, delivery_state,
                attempts, error, delivery_error, http_status, media, created_at, updated_at
                FROM contextra_event_artifacts WHERE payload->>'cameraId'='24'
                AND created_at >= %s ORDER BY created_at LIMIT 120''',(since,))
            rows=[dict(x) for x in cur.fetchall()]
        conn.rollback()
    return rows


client=redis.from_url(os.environ['CONTEXTRA_METADATA_REDIS_URL'],decode_responses=True,
                      socket_connect_timeout=1,socket_timeout=1,max_connections=1)
prefix=os.environ.get('CONTEXTRA_METADATA_NAMESPACE','contextra:metadata:v1')+':camera:'+hashlib.sha256(b'24').hexdigest()
key=prefix+':frames'
tail=client.xrevrange(key,count=1)
cursor=tail[0][0] if tail else '0-0'
initial_time=time.time()
prior_events=events(initial_time-120)
start=time.monotonic();started_ms=time.time_ns()//1000000
rows=[];statuses=[];errors=[];total_bytes=0;next_status=0
while time.monotonic()-start < 45:
    elapsed=time.monotonic()-start
    if elapsed>=next_status:
        raw=client.get(prefix+':status')
        statuses.append({'elapsed':elapsed,'at_ms':time.time_ns()//1000000,'status':json.loads(raw) if raw else None})
        next_status=elapsed+5
    try:
        batches=client.xread({key:cursor},count=100,block=250)
    except redis.exceptions.TimeoutError:
        errors.append({'elapsed':elapsed,'error':'REDIS_READ_TIMEOUT'});continue
    for _,entries in batches:
        for rid,fields in entries:
            cursor=rid
            raw=fields.get('json')
            if raw is None:continue
            row=json.loads(raw)
            assert str(row.get('cameraId'))=='24'
            total_bytes+=len(raw.encode())
            if total_bytes>32*1024**2 or len(rows)>=5000:
                raise RuntimeError('Bounded cache capacity exceeded')
            rows.append({'redis_id':rid,'observed_at_ms':time.time_ns()//1000000,'snapshot':row})
ended_ms=time.time_ns()//1000000;elapsed=time.monotonic()-start
raw=client.get(prefix+':status')
statuses.append({'elapsed':elapsed,'at_ms':ended_ms,'status':json.loads(raw) if raw else None})
client.close()
after_events=events(initial_time-120)
print(json.dumps({'started_ms':started_ms,'ended_ms':ended_ms,'elapsed_seconds':elapsed,
                  'capture_mode':'Redis XREAD without consumer group; GET; PostgreSQL read-only SELECT',
                  'video_recording':False,'model_or_rule_execution':False,'cache_bytes':total_bytes,
                  'statuses':statuses,'read_errors':errors,'frames':rows,'events_before':prior_events,
                  'events_after':after_events}))
