#!/usr/bin/env python3
from __future__ import annotations

import json
import os
import time
from datetime import datetime, timezone
from pathlib import Path

import requests

ROOT = Path('/root/projects/etsy-quiet-faith-collection/generated/premium_50_originals_no_resize')
EXP = ROOT / 'printify_nonshirt_product_expansion'
CREATED = EXP / 'created_nonshirt_products.json'
OUT = EXP / 'force_republish_linked_mugs_report.json'
ENV = Path('/root/.hermes/.env')

for line in ENV.read_text().splitlines():
    s = line.strip()
    if not s or s.startswith('#') or '=' not in s:
        continue
    k, v = s.split('=', 1)
    os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'"))

TOKEN = os.environ['PRINTIFY_API_TOKEN']
SHOP_ID = os.environ.get('PRINTIFY_SHOP_ID', '27001435')
BASE = 'https://api.printify.com/v1'
HEADERS = {'Authorization': f'Bearer {TOKEN}', 'Content-Type': 'application/json'}
SAFE_SCALES = {'white_mug_11oz': 0.38, 'black_mug_15oz': 0.40}
PUBLISH_IMAGES_ONLY = {
    'title': False,
    'description': False,
    'images': True,
    'variants': False,
    'tags': False,
    'keyFeatures': False,
    'shipping_template': False,
}


def api(method, url, **kwargs):
    for attempt in range(1, 5):
        r = requests.request(method, url, headers=HEADERS, timeout=180, **kwargs)
        if r.status_code in (429, 500, 502, 503, 504) and attempt < 4:
            time.sleep(5 * attempt)
            continue
        return r


def read_json(path: Path, default):
    try:
        return json.loads(path.read_text())
    except Exception:
        return default


def submitted_ids():
    ids = set()
    for name in ['publish_nonshirt_results_partial.json', 'publish_nonshirt_results.json']:
        for row in read_json(EXP / name, []):
            if row.get('printify_product_id') and row.get('publish_status') != 'error':
                ids.add(row['printify_product_id'])
    return ids


def main():
    created = read_json(CREATED, [])
    mugs = [x for x in created if x.get('lane') in SAFE_SCALES]
    submitted = submitted_ids()
    report = {
        'started_at': datetime.now(timezone.utc).isoformat(),
        'safe_scales': SAFE_SCALES,
        'total_mugs': len(mugs),
        'rows': [],
    }
    for i, row in enumerate(mugs, 1):
        pid = row['printify_product_id']
        lane = row['lane']
        target = SAFE_SCALES[lane]
        result = {'printify_product_id': pid, 'lane': lane, 'title': row.get('title'), 'target_scale': target}
        g = api('GET', f'{BASE}/shops/{SHOP_ID}/products/{pid}.json')
        result['get_http'] = g.status_code
        if g.status_code >= 300:
            result['error'] = g.text[:500]
            report['rows'].append(result)
            print(f'{i:03d}/{len(mugs)} GET_ERR {pid} {g.status_code}', flush=True)
            continue
        product = g.json()
        ext = product.get('external') or {}
        result['external_id'] = ext.get('id')
        result['external_handle'] = ext.get('handle')
        print_areas = product.get('print_areas') or []
        scales = []
        changed = False
        for area in print_areas:
            for ph in area.get('placeholders') or []:
                for img in ph.get('images') or []:
                    scales.append(img.get('scale'))
                    if img.get('scale') != target or img.get('x') != 0.5 or img.get('y') != 0.5 or img.get('angle') != 0:
                        img['x'] = 0.5
                        img['y'] = 0.5
                        img['scale'] = target
                        img['angle'] = 0
                        changed = True
        result['before_scales'] = scales
        result['placement_changed'] = changed
        if changed:
            u = api('PUT', f'{BASE}/shops/{SHOP_ID}/products/{pid}.json', json={'print_areas': print_areas})
            result['put_http'] = u.status_code
        else:
            result['put_http'] = 'not_needed'

        is_linked_or_submitted = bool(ext.get('id')) or pid in submitted
        result['linked_or_submitted'] = is_linked_or_submitted
        if is_linked_or_submitted:
            p = api('POST', f'{BASE}/shops/{SHOP_ID}/products/{pid}/publish.json', json=PUBLISH_IMAGES_ONLY)
            result['republish_images_http'] = p.status_code
            try:
                result['republish_images_response'] = p.json()
            except Exception:
                result['republish_images_response'] = p.text[:500]
        else:
            result['republish_images_http'] = 'skipped_not_yet_published'

        v = api('GET', f'{BASE}/shops/{SHOP_ID}/products/{pid}.json')
        result['verify_http'] = v.status_code
        if v.status_code < 300:
            vd = v.json()
            result['after_scales'] = [
                img.get('scale')
                for area in (vd.get('print_areas') or [])
                for ph in (area.get('placeholders') or [])
                for img in (ph.get('images') or [])
            ]
            result['mockup_src'] = (vd.get('images') or [{}])[0].get('src')
        report['rows'].append(result)
        OUT.write_text(json.dumps(report, indent=2))
        print(f"{i:03d}/{len(mugs)} {lane} {pid} scale={result.get('after_scales')} republish={result.get('republish_images_http')} linked={is_linked_or_submitted}", flush=True)
        time.sleep(0.25)

    rows = report['rows']
    report['finished_at'] = datetime.now(timezone.utc).isoformat()
    report['safe_scale_verified'] = sum(1 for r in rows if r.get('after_scales') == [r.get('target_scale')])
    report['linked_or_submitted_count'] = sum(1 for r in rows if r.get('linked_or_submitted'))
    report['republished_images_ok'] = sum(1 for r in rows if isinstance(r.get('republish_images_http'), int) and r['republish_images_http'] < 300)
    report['skipped_not_yet_published'] = sum(1 for r in rows if r.get('republish_images_http') == 'skipped_not_yet_published')
    report['errors'] = [r for r in rows if r.get('verify_http') != 200 or r.get('after_scales') != [r.get('target_scale')] or (isinstance(r.get('republish_images_http'), int) and r['republish_images_http'] >= 300)]
    OUT.write_text(json.dumps(report, indent=2))
    print(json.dumps({k: report[k] for k in ['total_mugs','safe_scale_verified','linked_or_submitted_count','republished_images_ok','skipped_not_yet_published']}, indent=2))
    if report['errors']:
        print(f"ERRORS: {len(report['errors'])}")
        raise SystemExit(1)


if __name__ == '__main__':
    main()
