#!/usr/bin/env python3
import datetime
import json
import os
import urllib.parse
import urllib.request
from pathlib import Path
from zoneinfo import ZoneInfo

ROOT = Path('/data/video-pipeline/HaTramAudio/project/029-Chiec-O-De-Lai-O-Tram-Xe-Buyt-Cuoi')
WORK = ROOT / 'work/upload/run-20260722T162951Z-87a939ad'
WORK.mkdir(parents=True, exist_ok=True)

def load_env(path):
    values = {}
    for raw in path.read_text().splitlines():
        line = raw.strip()
        if line and not line.startswith('#') and '=' in line:
            key, value = line.split('=', 1)
            values[key.strip()] = value.strip().strip('"\'')
    return values

env = dict(os.environ)
for key, value in load_env(Path.home()/'.config/ha-tram-audio/postiz.env').items():
    env.setdefault(key, value)
required = ['POSTIZ_BASE_URL','POSTIZ_API_KEY','POSTIZ_FACEBOOK_INTEGRATION_ID','POSTIZ_YOUTUBE_INTEGRATION_ID','POSTIZ_TIMEZONE','POSTIZ_SLOTS']
missing = [key for key in required if not env.get(key)]
if missing:
    raise SystemExit(f'missing required config: {missing}')
base = env['POSTIZ_BASE_URL'].rstrip('/')
headers = {'Authorization': env['POSTIZ_API_KEY']}

def get(path):
    request = urllib.request.Request(base + path, headers=headers)
    with urllib.request.urlopen(request, timeout=60) as response:
        return response.status, json.load(response)

def items(data, keys):
    if isinstance(data, list):
        return data
    if isinstance(data, dict):
        for key in keys:
            if isinstance(data.get(key), list):
                return data[key]
    return []

status, connected = get('/is-connected')
if status != 200 or connected.get('connected') is not True:
    raise SystemExit('Postiz is not connected')
_, raw_integrations = get('/integrations')
integrations = items(raw_integrations, ['integrations','data'])
fb = env['POSTIZ_FACEBOOK_INTEGRATION_ID']; yt = env['POSTIZ_YOUTUBE_INTEGRATION_ID']; targets = {fb, yt}
selected = [x for x in integrations if x.get('id') in targets]
if {x.get('id') for x in selected} != targets or any(x.get('disabled') is True for x in selected):
    raise SystemExit('target integrations missing or disabled')
byid={x.get('id'):x for x in selected}
def provider(x): return str(x.get('identifier') or x.get('providerIdentifier') or x.get('provider') or '').lower()
if 'facebook' not in provider(byid[fb]) or 'youtube' not in provider(byid[yt]):
    raise SystemExit('target integration platform mismatch')
if any(str(x.get('name') or '') != 'Hạ Trâm Audio' for x in selected):
    raise SystemExit('target integration name mismatch')
now = datetime.datetime.now(datetime.timezone.utc)
end = now + datetime.timedelta(days=30)
query = urllib.parse.urlencode({'startDate': now.isoformat().replace('+00:00','Z'), 'endDate': end.isoformat().replace('+00:00','Z')})
_, raw_posts = get('/posts?' + query)
posts = items(raw_posts, ['posts','data'])
filtered = [p for p in posts if (p.get('integration') or {}).get('id') in targets]
ignored = len(posts) - len(filtered)
occupied = {fb:set(), yt:set()}
for post in filtered:
    state = str(post.get('state','')).upper()
    if state not in {'QUEUE','PUBLISHED'}:
        continue
    value = post.get('publishDate')
    if not value:
        continue
    if value.endswith('Z'):
        dt = datetime.datetime.fromisoformat(value[:-1] + '+00:00')
    else:
        dt = datetime.datetime.fromisoformat(value)
        if dt.tzinfo is None:
            dt = dt.replace(tzinfo=datetime.timezone.utc)
    occupied[(post.get('integration') or {}).get('id')].add(dt.astimezone(datetime.timezone.utc).replace(microsecond=0))
tz = ZoneInfo(env['POSTIZ_TIMEZONE'])
slots = []
for value in env['POSTIZ_SLOTS'].split(','):
    hour, minute = map(int, value.strip().split(':'))
    slots.append((hour,minute))
local_now = now.astimezone(tz)
choice = None
for day_offset in range(31):
    date = local_now.date() + datetime.timedelta(days=day_offset)
    for hour,minute in sorted(slots):
        local = datetime.datetime(date.year,date.month,date.day,hour,minute,tzinfo=tz)
        if local <= local_now:
            continue
        utc = local.astimezone(datetime.timezone.utc).replace(microsecond=0)
        if utc not in occupied[fb] and utc not in occupied[yt]:
            choice = (local,utc)
            break
    if choice: break
if not choice:
    raise SystemExit('no common slot in 31 days')
find_slots = {}
for integration in targets:
    try:
        _, body = get('/find-slot/' + urllib.parse.quote(integration))
        find_slots[integration] = body.get('date') if isinstance(body,dict) else None
    except Exception as exc:
        find_slots[integration] = f'error:{type(exc).__name__}'
receipt = {
    'schema_version':1,'project_id':'029-Chiec-O-De-Lai-O-Tram-Xe-Buyt-Cuoi','run_id':'run-20260722T162951Z-87a939ad','status':'completed','verified':True,'checked_at':now.isoformat(),
    'target_integrations':[{'id':x.get('id'),'name':x.get('name'),'provider':provider(x),'disabled':x.get('disabled')} for x in selected],
    'slot_local':choice[0].isoformat(),'slot_utc':choice[1].isoformat().replace('+00:00','Z'),
    'occupied_counts':{fb:len(occupied[fb]),yt:len(occupied[yt])},
    'ignored_other_integration_posts':ignored,'find_slot_reference':find_slots,
}
(WORK/'preflight.json').write_text(json.dumps(receipt,ensure_ascii=False,indent=2)+'\n')
print(json.dumps(receipt,ensure_ascii=False))
