#!/usr/bin/env python3
import http.client
import json
import mimetypes
import secrets
import ssl
import sys
from datetime import datetime, timezone
from pathlib import Path
from urllib.parse import urlparse

PROJECT = Path('/data/video-pipeline/Chanel-HuyenAnAudio/project/003-Co-Chu-Tro-Bi-Ep-Ban-Nha-Bay-Chia-Khoa-Bong-Tro-Ve')
CONFIG = Path.home() / '.config/huyen-an-audio/postiz.env'
RECEIPT = PROJECT / 'log/postiz-media.json'
MEDIA = [('video', PROJECT / 'output/final-upload.mp4'), ('thumbnail', PROJECT / 'image/intro-poster-1920x1080.png')]


def load_env():
    values = {}
    for raw in CONFIG.read_text(encoding='utf-8').splitlines():
        line = raw.strip()
        if not line or line.startswith('#') or '=' not in line:
            continue
        key, value = line.split('=', 1)
        values[key.strip()] = value.strip().strip('"').strip("'")
    return values


def upload(base, api_key, path):
    parsed = urlparse(base)
    if parsed.scheme not in {'http', 'https'}:
        raise RuntimeError('Unsupported Postiz scheme')
    boundary = '----HermesPostiz' + secrets.token_hex(16)
    mime = mimetypes.guess_type(path.name)[0] or 'application/octet-stream'
    prefix = (
        f'--{boundary}\r\n'
        f'Content-Disposition: form-data; name="file"; filename="{path.name}"\r\n'
        f'Content-Type: {mime}\r\n\r\n'
    ).encode('utf-8')
    suffix = f'\r\n--{boundary}--\r\n'.encode('ascii')
    length = len(prefix) + path.stat().st_size + len(suffix)
    host = parsed.hostname
    port = parsed.port
    connection = (
        http.client.HTTPSConnection(host, port, timeout=7200, context=ssl.create_default_context())
        if parsed.scheme == 'https'
        else http.client.HTTPConnection(host, port, timeout=7200)
    )
    base_path = parsed.path.rstrip('/')
    target = base_path + '/upload'
    connection.putrequest('POST', target)
    connection.putheader('Authorization', api_key)
    connection.putheader('Content-Type', f'multipart/form-data; boundary={boundary}')
    connection.putheader('Content-Length', str(length))
    connection.endheaders()
    connection.send(prefix)
    sent = 0
    with path.open('rb') as handle:
        while True:
            block = handle.read(8 * 1024 * 1024)
            if not block:
                break
            connection.send(block)
            sent += len(block)
            if sent and sent % (512 * 1024 * 1024) < 8 * 1024 * 1024:
                print(json.dumps({'asset': path.name, 'sent_bytes': sent, 'total_bytes': path.stat().st_size}), flush=True)
    connection.send(suffix)
    response = connection.getresponse()
    raw = response.read()
    status = response.status
    connection.close()
    if not 200 <= status < 300:
        body = raw.decode(errors='replace')[:1000]
        raise RuntimeError(f'Postiz upload HTTP {status}: {body}')
    data = json.loads(raw.decode('utf-8'))
    item = data.get('media') or data.get('data') or data
    if isinstance(item, list):
        item = item[0] if item else None
    if not isinstance(item, dict) or not item.get('id') or not item.get('path'):
        raise RuntimeError('Postiz upload response missing media id/path')
    return {'id': item['id'], 'path': item['path'], 'name': path.name, 'bytes': path.stat().st_size}


def save(canon, media, verified=False):
    data = {'version': 1, 'verified': verified, 'source_canon_sha256': canon, 'media': media, 'updated_at': datetime.now(timezone.utc).isoformat()}
    RECEIPT.write_text(json.dumps(data, ensure_ascii=False, indent=2) + '\n')


def main():
    env = load_env(); base = env.get('POSTIZ_BASE_URL'); key = env.get('POSTIZ_API_KEY')
    if not base or not key:
        raise SystemExit('Postiz config incomplete')
    canon = json.loads((PROJECT / 'story/promotion-report.json').read_text())['spoken_sha256']
    transcode = json.loads((PROJECT / 'log/upload-transcode.json').read_text())
    upload_copy = PROJECT / 'output/final-upload.mp4'
    if (
        transcode.get('verified') is not True
        or transcode.get('source_canon_sha256') != canon
        or transcode.get('server_verification', {}).get('under_one_gb') is not True
        or not upload_copy.exists()
        or upload_copy.stat().st_size >= 1_000_000_000
    ):
        raise RuntimeError('Upload copy is not verified below 1,000,000,000 bytes for current canon')
    media = {}
    if RECEIPT.exists():
        existing = json.loads(RECEIPT.read_text())
        if existing.get('source_canon_sha256') == canon:
            media = existing.get('media', {})
    for name, path in MEDIA:
        if name in media and media[name].get('id') and media[name].get('path'):
            print(json.dumps({'asset': name, 'status': 'reused_from_project_receipt', 'id': media[name]['id']}), flush=True)
            continue
        if not path.exists() or path.stat().st_size <= 0:
            raise RuntimeError(f'Missing media: {path}')
        media[name] = upload(base, key, path)
        save(canon, media, False)
        print(json.dumps({'asset': name, 'status': 'uploaded', 'id': media[name]['id'], 'bytes': media[name]['bytes']}), flush=True)
    verified = set(media) == {name for name, _ in MEDIA}
    save(canon, media, verified)
    print(json.dumps({'verified': verified, 'assets': list(media), 'receipt': str(RECEIPT)}, ensure_ascii=False))
    return 0 if verified else 1


if __name__ == '__main__':
    raise SystemExit(main())
