#!/usr/bin/env python3
from __future__ import annotations
import json, os, time
from pathlib import Path
from datetime import datetime, timezone
import requests

ENV=Path('/root/.hermes/.env')
for line in ENV.read_text().splitlines():
    s=line.strip()
    if s and not s.startswith('#') and '=' in s:
        k,v=s.split('=',1); os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'"))
ROOT=Path('/root/projects/etsy-quiet-faith-collection/generated/premium_50_originals_no_resize')
EXP=ROOT/'personalized_50_product_family_options'/'text_on_picture_style_launch_assets'/'printify_first50_personalized'
CREATED=EXP/'created_personalized_first50.json'
ACTIVE=EXP/'active_personalized_etsy_listings.json'
REPORT=EXP/'price_update_1799_report_v2.json'
TARGET=1799
SHOP=os.environ.get('PRINTIFY_SHOP_ID','27001435')
TOKEN=os.environ['PRINTIFY_API_TOKEN']
PBASE='https://api.printify.com/v1'
PH={'Authorization':f'Bearer {TOKEN}','Content-Type':'application/json'}
PUBLISH_PRICE_PAYLOAD={'title':False,'description':False,'images':False,'variants':True,'tags':False,'keyFeatures':False,'shipping_template':False}

def save_env_var(key,val):
    lines=ENV.read_text().splitlines() if ENV.exists() else []
    out=[]; found=False
    for line in lines:
        if line.startswith(key+'='):
            out.append(f'{key}={val}'); found=True
        else: out.append(line)
    if not found: out.append(f'{key}={val}')
    ENV.write_text('\n'.join(out)+'\n'); os.environ[key]=val

def refresh_etsy_token():
    c=os.environ.get('ETSY_CLIENT_ID'); s=os.environ.get('ETSY_CLIENT_SECRET'); rt=os.environ.get('ETSY_REFRESH_TOKEN')
    if not c or not rt: return False
    data={'grant_type':'refresh_token','client_id':c,'refresh_token':rt}
    if s: data['client_secret']=s
    r=requests.post('https://api.etsy.com/v3/public/oauth/token',data=data,timeout=30)
    if r.status_code!=200: return False
    d=r.json(); save_env_var('ETSY_ACCESS_TOKEN',d['access_token'])
    if d.get('refresh_token'): save_env_var('ETSY_REFRESH_TOKEN',d['refresh_token'])
    return True

def etsy_key():
    c=os.environ.get('ETSY_CLIENT_ID'); s=os.environ.get('ETSY_CLIENT_SECRET')
    return f'{c}:{s}' if c and s else c

def req(method,url,headers=None,**kw):
    for a in range(1,4):
        r=requests.request(method,url,headers=headers,timeout=90,**kw)
        if r.status_code in (429,500,502,503,504) and a<3:
            time.sleep(5*a); continue
        return r

def safe(r):
    try: return r.json()
    except Exception: return r.text[:800]

def get_product(pid):
    return req('GET', f'{PBASE}/shops/{SHOP}/products/{pid}.json', headers=PH)

def put_product_prices(pid, variants):
    payload={'variants':[{'id':v['id'],'price':TARGET,'is_enabled':v.get('is_enabled',True)} for v in variants if v.get('is_enabled') or v.get('id')]}
    return req('PUT', f'{PBASE}/shops/{SHOP}/products/{pid}.json', headers=PH, json=payload)

def publish_prices(pid):
    return req('POST', f'{PBASE}/shops/{SHOP}/products/{pid}/publish.json', headers=PH, json=PUBLISH_PRICE_PAYLOAD)

def get_inventory(lid):
    r=req('GET', f'https://openapi.etsy.com/v3/application/listings/{lid}/inventory', headers={'x-api-key':etsy_key(),'Authorization':'Bearer '+os.environ.get('ETSY_ACCESS_TOKEN','')})
    if r.status_code==401 and refresh_etsy_token():
        r=req('GET', f'https://openapi.etsy.com/v3/application/listings/{lid}/inventory', headers={'x-api-key':etsy_key(),'Authorization':'Bearer '+os.environ.get('ETSY_ACCESS_TOKEN','')})
    return r

def inventory_prices(inv):
    prices=[]
    for p in inv.get('products',[]) or []:
        for off in p.get('offerings',[]) or []:
            pr=off.get('price') or {}
            prices.append(pr.get('amount'))
    return prices

def main():
    created=json.loads(CREATED.read_text())
    active=json.loads(ACTIVE.read_text()) if ACTIVE.exists() else []
    active_by_pid={x.get('printify_product_id'):str(x.get('listing_id')) for x in active if x.get('listing_id')}
    refresh_etsy_token()
    rows=[]
    for item in created:
        pid=item.get('printify_product_id') or item.get('response',{}).get('id')
        row={'sku_product':item.get('sku_product'),'phrase':item.get('base_phrase'),'pid':pid}
        g=get_product(pid); row['get_http']=g.status_code
        if g.status_code!=200:
            row['get_body']=safe(g); rows.append(row); continue
        d=g.json(); ext=d.get('external') or {}; lid=str(ext.get('id') or active_by_pid.get(pid) or '')
        enabled=[v for v in d.get('variants',[]) if v.get('is_enabled')]
        row['variant_ids']=[v.get('id') for v in enabled]
        row['before_prices']=[v.get('price') for v in enabled]
        put=put_product_prices(pid, enabled); row['put_http']=put.status_code
        if put.status_code>=300: row['put_body']=safe(put)
        g2=get_product(pid); row['after_get_http']=g2.status_code
        if g2.status_code==200:
            d2=g2.json(); enabled2=[v for v in d2.get('variants',[]) if v.get('is_enabled')]
            row['after_prices']=[v.get('price') for v in enabled2]
            ext2=d2.get('external') or {}; lid=str(ext2.get('id') or lid)
        if lid:
            row['listing_id']=lid
            pub=publish_prices(pid); row['publish_price_http']=pub.status_code
            if pub.status_code>=300: row['publish_price_body']=safe(pub)
            # wait a moment for inventory to reflect, then verify
            time.sleep(1)
            inv=get_inventory(lid); row['inventory_http']=inv.status_code
            if inv.status_code==200:
                row['etsy_inventory_prices']=inventory_prices(inv.json())
            else:
                row['inventory_body']=safe(inv)
        rows.append(row)
        REPORT.write_text(json.dumps({'updated_at':datetime.now(timezone.utc).isoformat(),'target_cents':TARGET,'results':rows}, indent=2))
        time.sleep(0.15)
    # update all local manifest variant price fields, not only a fixed variant id
    local_changes=0
    for item in created:
        for ck in ('payload','response'):
            cont=item.get(ck)
            if isinstance(cont,dict):
                for v in cont.get('variants',[]) or []:
                    if 'price' in v and v['price'] != TARGET:
                        v['price']=TARGET; local_changes+=1
    CREATED.write_text(json.dumps(created, indent=2))
    summary={
        'target_price':'17.99',
        'total':len(created),
        'printify_ok':sum(1 for r in rows if r.get('put_http')==200 and set(r.get('after_prices') or [])=={TARGET}),
        'printify_errors':sum(1 for r in rows if r.get('put_http')!=200),
        'linked':sum(1 for r in rows if r.get('listing_id')),
        'etsy_inventory_verified_1799':sum(1 for r in rows if r.get('etsy_inventory_prices') and set(r.get('etsy_inventory_prices'))=={TARGET}),
        'local_manifest_changes':local_changes,
        'report':str(REPORT)
    }
    REPORT.write_text(json.dumps({'summary':summary,'updated_at':datetime.now(timezone.utc).isoformat(),'target_cents':TARGET,'results':rows}, indent=2))
    print(json.dumps(summary,indent=2))
if __name__=='__main__': main()
