# -*- coding: utf-8 -*-
"""
Crea tarjeta en Trello board rH2kazG2 (editor de videos), lista Input,
con cover producto + 6 PDFs + 5 mp4 + 1 txt body copy (Ecoden no tiene video).

Devuelve JSON: {"card_id": "...", "short_url": "...", "attachments_count": int}
"""
import io, os, sys, json, time, datetime
import requests

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

KEY = 'd72121bbecb3634a9a7d8a31b24b8550'
TOKEN = 'ATTA71c15300bac07eac27c965971d7c714a690daed23bab7fea83076917f46e8689F9C43023'
BOARD_ID = 'rH2kazG2'
LIST_ID = '69dfeb002c3e1d314649ff84'  # Input list

WORK = r"C:\Users\ferna\proyecto cero\_factory_3d_demo\_runs\flow_2026-05-09T22-23-35-000Z_ComfortSleep\_trello_card_input"
COVER = os.path.join(WORK, '_producto_imagen.jpg')
BRIEFS_DIR = os.path.join(WORK, 'briefs')

ATTACHMENTS = [
    # mp4s by finalist
    {'n': 1, 'kind': 'txt', 'path': os.path.join(WORK, 'NO_MP4__ad_text_only_body_copy_below.txt'),
     'name': 'V1_REF__Ecoden_Dr_Alexander_Grant__NO_MP4_text_only.txt'},
    {'n': 2, 'kind': 'mp4', 'path': os.path.join(WORK, 'V2_thePillowHome_PT_gap_cervical_903351665947429.mp4'),
     'name': 'V2_REF_thePillowHome_gap_cervical_903351665947429.mp4'},
    {'n': 3, 'kind': 'mp4', 'path': os.path.join(WORK, 'V3_drRalphChiropractor25y_dual_height_80634156.mp4'),
     'name': 'V3_REF_drRalph_chiropractor_25y_Mello_80634156.mp4'},
    {'n': 4, 'kind': 'mp4', 'path': os.path.join(WORK, 'V4_dailyWellness_cervicalTraction_84922360.mp4'),
     'name': 'V4_REF_DailyWellness_CervicalTraction_84922360.mp4'},
    {'n': 5, 'kind': 'mp4', 'path': os.path.join(WORK, 'V5_NoctisRest_ES_15000personas_1470376311155120.mp4'),
     'name': 'V5_REF_NoctisRest_ES_15000_personas_1470376311155120.mp4'},
    {'n': 6, 'kind': 'mp4', 'path': os.path.join(WORK, 'V6_AnthonyMoll_testimonio_mello_88110246.mp4'),
     'name': 'V6_REF_AnthonyMoll_testimonio_mello_88110246.mp4'},
    # 6 briefs
    {'n': 1, 'kind': 'pdf', 'path': os.path.join(BRIEFS_DIR, 'V1_brief_fb_26302749462678505.pdf'),
     'name': 'V1_BRIEF_ComfortSleep_Ecoden_authority.pdf'},
    {'n': 2, 'kind': 'pdf', 'path': os.path.join(BRIEFS_DIR, 'V2_brief_fb_903351665947429.pdf'),
     'name': 'V2_BRIEF_ComfortSleep_thePillowHome_gap.pdf'},
    {'n': 3, 'kind': 'pdf', 'path': os.path.join(BRIEFS_DIR, 'V3_brief_gh_80634156.pdf'),
     'name': 'V3_BRIEF_ComfortSleep_drRalph_dual_height.pdf'},
    {'n': 4, 'kind': 'pdf', 'path': os.path.join(BRIEFS_DIR, 'V4_brief_gh_84922360.pdf'),
     'name': 'V4_BRIEF_ComfortSleep_cervical_traction.pdf'},
    {'n': 5, 'kind': 'pdf', 'path': os.path.join(BRIEFS_DIR, 'V5_brief_fb_1470376311155120.pdf'),
     'name': 'V5_BRIEF_ComfortSleep_NoctisRest_ES.pdf'},
    {'n': 6, 'kind': 'pdf', 'path': os.path.join(BRIEFS_DIR, 'V6_brief_gh_88110246.pdf'),
     'name': 'V6_BRIEF_ComfortSleep_testimonio_arriesgado.pdf'},
]


def main():
    today = datetime.date.today().isoformat()  # 2026-05-10
    title = f"ComfortSleep · Escalado Formatos · 6 finalistas (5 similares + 1 arriesgado) · {today}"

    desc = (
        "## ComfortSleep · Escalado Formatos · 6 finalistas\n\n"
        "**Producto:** ComfortSleep · almohada cervical con reborde frontal y hendidura central\n"
        "**País:** España (ES) · idioma castellano peninsular\n"
        "**Avatar:** 35-60 años (foco 40-55), ambos géneros con ligero sesgo femenino, "
        "adultos con cefalea matutina / dolor cervical crónico que ya pasaron por el médico\n"
        "**COD nativo:** envío 24-48h · pago contra reembolso · cero precio en speech\n\n"
        "---\n\n"
        "### CONTEXTO – Análisis del video ganador (origen del flow)\n\n"
        "Video original ES de ComfortSleep escalado: talking-head fisioterapeuta uniforme blanco "
        "en consulta clínica + B-roll producto + B-roll persona durmiendo de lado. Speech 25s. "
        "Hook: \"Te despiertas con dolor de cabeza casi cada día. El médico dice que es estrés, "
        "pero siempre empieza cuando te acuestas\". Reframe causa-raíz: la cefalea matutina no es "
        "estrés, es la almohada. Mecanismo: reborde frontal que mantiene cuello en posición neutral. "
        "Awareness Problem Aware (Schwartz 2) con puente a Solution Aware vía reframe. Sofisticación 3. "
        "Cierre: \"La recibes en 24-48h y pagas al repartidor\".\n\n"
        "Jergas activadas: cefalea matutina · dolor en la nuca · el médico dice que es estrés · "
        "posición neutral del cuello · reborde frontal · gap cervical · un tercio de tu vida.\n\n"
        "---\n\n"
        "### LOS 6 FINALISTAS (validación numérica REGLA #93)\n\n"
        "| # | Rol | Score | Brand | País | Días esc. | Awareness | Sof | Fuente |\n"
        "|---|-----|-------|-------|------|-----------|-----------|-----|--------|\n"
        "| V1 | similar | 0.97 | Ecoden Dreams (Dr. Alexander Grant) | USA | 49 | Sol→Most Aware | 3 | apify+meta |\n"
        "| V2 | similar | 0.95 | The Pillow Home (gap cervical) | UK+USA | 60 | Prob→Sol Aware | 3 | apify+meta |\n"
        "| V3 | similar | 0.92 | Mello (Dr. Ralph chiropractor 25y) | USA | 102 | Sol Aware | 3 | gethookd |\n"
        "| V4 | similar | 0.86 | Daily Wellness (cervical traction) | USA | 89 | Sol Aware | 3 | gethookd |\n"
        "| V5 | similar | 0.84 | Noctis Rest (asistente fisio ES) | ES | 28 | Prob→Sol Aware | 3 | apify+meta |\n"
        "| V6 | **arriesgado** | 0.78 | Mello (Anthony Moll testimonio 1ª persona) | USA | 92 | Problem Aware | 3 | gethookd |\n\n"
        "---\n\n"
        "### URLs ORIGINALES (solo trazabilidad — NO referencia para editor REGLA #45)\n\n"
        "1. V1 — https://www.facebook.com/ads/library/?id=26302749462678505\n"
        "2. V2 — https://www.facebook.com/ads/library/?id=903351665947429\n"
        "3. V3 — https://app.gethookd.ai/share/ad/80634156\n"
        "4. V4 — https://app.gethookd.ai/share/ad/84922360\n"
        "5. V5 — https://www.facebook.com/ads/library/?id=1470376311155120\n"
        "6. V6 — https://app.gethookd.ai/share/ad/88110246\n\n"
        "---\n\n"
        "### QUÉ HACE EL EDITOR\n\n"
        "Para cada uno de los 6 finalistas hay 1 PDF brief con 3 secciones (referencia + "
        "explicación + speech transmutado al producto/mercado/avatar). El speech está cerrado, "
        "en castellano peninsular neutro, sin precio, con cierre canónico COD \"pagas en la "
        "puerta de tu casa cuando llega\".\n\n"
        "5 referentes son **similares** al ganador (talking-head autoridad médica/fisio + "
        "reframe causa-raíz). El **6º es arriesgado**: testimonio en 1ª persona del propio "
        "usuario (NO autoridad médica) — el editor debe preservar ese giro y producirlo como "
        "selfie/POV usuario español 40-55, no como talking-head clínico.\n\n"
        "**V1 Ecoden:** ese referente es texto+imagen (no tiene video original), por eso NO lleva "
        "mp4 adjunto sino un .txt con la body copy literal. El speech transmutado en el PDF V1 "
        "es lo que se graba como talking-head fisio español.\n\n"
        "**Deadline:** 48h desde recepción.\n\n"
        f"**Flow ID:** flow_2026-05-09T22-23-35-000Z_ComfortSleep · creado {today}"
    )

    # Verify desc length is reasonable
    print(f"desc length: {len(desc)} chars")

    # 1. Create card
    print("[1/3] Creating card...")
    r = requests.post(
        'https://api.trello.com/1/cards',
        params={
            'key': KEY,
            'token': TOKEN,
            'idList': LIST_ID,
            'name': title,
            'desc': desc,
            'pos': 'top',
        }
    )
    if r.status_code != 200:
        print(f"FAIL create card: {r.status_code} {r.text}")
        sys.exit(1)
    card = r.json()
    card_id = card['id']
    short_url = card['shortUrl']
    print(f"  card_id: {card_id}")
    print(f"  short_url: {short_url}")

    # 2. Upload cover with setCover=true
    print("[2/3] Uploading cover image...")
    with open(COVER, 'rb') as fh:
        r = requests.post(
            f'https://api.trello.com/1/cards/{card_id}/attachments',
            params={'key': KEY, 'token': TOKEN, 'setCover': 'true', 'name': '_cover_ComfortSleep.jpg'},
            files={'file': ('_cover_ComfortSleep.jpg', fh, 'image/jpeg')},
            timeout=120,
        )
    if r.status_code not in (200, 201):
        print(f"FAIL cover: {r.status_code} {r.text[:300]}")
        # continue anyway
    else:
        cov_id = r.json().get('id')
        print(f"  cover OK: {cov_id}")
        # Set as card cover explicitly
        r2 = requests.put(
            f'https://api.trello.com/1/cards/{card_id}',
            params={'key': KEY, 'token': TOKEN, 'idAttachmentCover': cov_id}
        )
        print(f"  setCover response: {r2.status_code}")

    # 3. Upload other attachments
    print("[3/3] Uploading 12 attachments (5 mp4 + 6 PDF + 1 txt)...")
    success = 0
    failures = []
    for a in ATTACHMENTS:
        path = a['path']
        name = a['name']
        if not os.path.exists(path):
            print(f"  MISSING: {name} -> skipped")
            failures.append(name)
            continue
        size = os.path.getsize(path)
        print(f"  uploading {name} ({size//1024} KB)...")
        mime = 'video/mp4' if a['kind'] == 'mp4' else ('application/pdf' if a['kind'] == 'pdf' else 'text/plain')
        try:
            with open(path, 'rb') as fh:
                r = requests.post(
                    f'https://api.trello.com/1/cards/{card_id}/attachments',
                    params={'key': KEY, 'token': TOKEN, 'name': name},
                    files={'file': (name, fh, mime)},
                    timeout=600,
                )
            if r.status_code in (200, 201):
                success += 1
                print(f"    OK")
            else:
                print(f"    FAIL: {r.status_code} {r.text[:200]}")
                failures.append(name)
        except Exception as e:
            print(f"    EXC: {e}")
            failures.append(name)
        time.sleep(0.5)

    # Final attachments count
    r = requests.get(f'https://api.trello.com/1/cards/{card_id}/attachments', params={'key': KEY, 'token': TOKEN})
    atts = r.json() if r.status_code == 200 else []
    final_count = len(atts)
    print(f"Final attachments: {final_count}")

    # Output JSON
    out = {
        'card_id': card_id,
        'short_url': short_url,
        'attachments_count': final_count,
        'board_id': BOARD_ID,
        'list_id': LIST_ID,
        'title': title,
        'success_uploads': success,
        'failures': failures,
    }
    out_path = os.path.join(WORK, '_trello_card.json')
    with open(out_path, 'w', encoding='utf-8') as fh:
        json.dump(out, fh, ensure_ascii=False, indent=2)
    print(f"\nOUTPUT JSON: {out_path}")
    print(json.dumps({'card_id': card_id, 'short_url': short_url, 'attachments_count': final_count}, ensure_ascii=False))


if __name__ == '__main__':
    main()
