#!/usr/bin/env python3
"""Question « Partager cette avancee ? » au premier parcours COMMENCE PAR LE CREATEUR (decision de Sebastien, 18/10/2026) : gratuit, offert, credit ou paye, le paiement n'entre pas en ligne de compte ;
confirmation de paiement (parcours_start_paid), inscription par une page de vente, demarrage direct ; une attribution de l'administration n'est pas un demarrage par le createur."""
import json, os, re, subprocess, sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from lib import ROOT, call, mk_user, ok, reset_rate_limits, sql, summary

def section(t): print('\n■ ' + t); reset_rate_limits()
def posts(uid): return [r.split('\t') for r in sql(f"SELECT id, auto_event FROM posts WHERE user_id = '{uid}' AND kind = 'auto' ORDER BY id").split('\n') if r.strip()]
def php(code): return subprocess.run(['php', '-d', 'display_errors=0', '-r', '$_SERVER["REQUEST_METHOD"]="GET"; require "api/_parcours_paid.php"; ' + code], capture_output=True, text=True, cwd=ROOT).stdout.strip()
def paid(uid, pid='PAR-01', pi='pi_test_1'): return json.loads(php(f'echo json_encode(parcours_start_paid(db(), "{uid}", "{pid}", "{pi}"));'))
def row(uid, pid='PAR-01'): return sql(f"SELECT CONCAT(status, '|', COALESCE(payment_intent_id, '-')) FROM user_parcours WHERE user_id = '{uid}' AND parcours_id = '{pid}'")
def optin(who, share=True): st, d, _ = call('PUT', who, '/auto-posts/preference', {'share': share}); assert st == 200, (st, d)
def wipe():
    p = "'ps\\_%'"; e = "'ps\\_insc%@example.test'"
    sql(f"DELETE FROM refresh_tokens WHERE user_id COLLATE utf8mb4_unicode_ci IN (SELECT id FROM users WHERE id LIKE {p} OR email LIKE {e})")          # refresh_tokens est en utf8mb4_general_ci, users en utf8mb4_unicode_ci
    sql(f"DELETE FROM auto_post_refs WHERE user_id IN (SELECT id FROM users WHERE id LIKE {p} OR email LIKE {e}); DELETE FROM posts WHERE user_id IN (SELECT id FROM users WHERE id LIKE {p} OR email LIKE {e})")
    sql(f"DELETE FROM user_parcours WHERE user_id IN (SELECT id FROM users WHERE id LIKE {p} OR email LIKE {e}); DELETE FROM artisan_gallery WHERE user_id IN (SELECT id FROM users WHERE email LIKE {e})")
    sql(f"DELETE FROM notification_prefs WHERE user_id IN (SELECT id FROM users WHERE id LIKE {p} OR email LIKE {e}); DELETE FROM users WHERE id LIKE {p} OR email LIKE {e}")

wipe()
for uid, f in (('ps_a', 'Ana'), ('ps_b', 'Bob'), ('ps_c', 'Cleo'), ('ps_d', 'Dan'), ('ps_free', 'Free'), ('ps_adm', 'Adm')): mk_user(uid, 'admin' if uid == 'ps_adm' else 'client_essentiel', f, 'Test')
sql("UPDATE users SET created_at = NOW() - INTERVAL 60 DAY WHERE id LIKE 'ps\\_%'")
PROMPT = {'share_prompt': {'ref_type': 'parcours', 'ref_id': 'PAR-01', 'event': 'started'}}

section("Parcours payé (confirmation de paiement) : la même question")
r = paid('ps_a'); ok(r == PROMPT and row('ps_a') == 'active|pi_test_1' and not posts('ps_a'), 'membre qui n\'a pas répondu : le parcours démarre, la question est posée (share_prompt), rien n\'est publié')
optin('ps_b'); r = paid('ps_b'); ok(r is None and len(posts('ps_b')) == 1 and posts('ps_b')[0][1] == 'parcours_started' and row('ps_b') == 'active|pi_test_1', 'membre qui a dit oui : la publication « parcours démarré » part, plus de question')
r = paid('ps_b', pi='pi_test_2'); ok(r is None and len(posts('ps_b')) == 1 and row('ps_b') == 'active|pi_test_2', 'confirmation rejouée (double clic, rejeu du paiement) : UNE seule publication')
optin('ps_c', False); r = paid('ps_c'); ok(r is None and not posts('ps_c') and row('ps_c') == 'active|pi_test_1', 'membre qui a dit non : le parcours démarre, rien n\'est publié, aucune question')
r = paid('ps_d', pid='PAR-INCONNU'); ok(r is None and not posts('ps_d') and row('ps_d', 'PAR-INCONNU') == 'active|pi_test_1', 'un parcours qui n\'existe pas au catalogue : aucune question, aucune publication (et le démarrage garde son comportement)')

section("Gratuit, offert, crédit, payé : le même comportement")
st, d, _ = call('POST', 'ps_free', '/parcours/PAR-01/start', {}); free_prompt = {'share_prompt': d.get('share_prompt')} if d.get('share_prompt') else None
ok(st == 200 and d.get('ok') is True and free_prompt == PROMPT, 'démarrage direct (gratuit ou offert) : la même question, de la même forme')
ok(free_prompt is not None and free_prompt == paid('ps_a', pi='pi_test_3'), 'le démarrage payé et le démarrage direct renvoient EXACTEMENT la même question : le paiement n\'entre pas en ligne de compte')
sql("DELETE FROM user_parcours WHERE user_id = 'ps_free'"); optin('ps_free'); call('POST', 'ps_free', '/parcours/PAR-01/start', {}); a = posts('ps_free'); sql("DELETE FROM posts WHERE user_id = 'ps_b'; DELETE FROM auto_post_refs WHERE user_id = 'ps_b'; DELETE FROM user_parcours WHERE user_id = 'ps_b'"); paid('ps_b')
ok(len(a) == 1 and a[0][1] == 'parcours_started' and len(posts('ps_b')) == 1 and posts('ps_b')[0][1] == 'parcours_started', 'avec un accord : gratuit et payé publient exactement la même chose (« parcours démarré »)')
ok(php('echo json_encode(array_keys(auto_posts_pref(db(), "ps_a")));') == '["share","visibility","decided_at","hide_auto"]', 'l\'accord ne dépend que du membre (share, visibility, date, et son réglage de lecture hide_auto), jamais d\'un paiement')

section("Inscription par une page de vente de parcours")
em = 'ps_insc1@example.test'; st, d, _ = call('POST', None, '/parcours-inscription', {'name': 'Iris Insc', 'email': em, 'marque': 'Atelier Iris', 'craft': 'céramique', 'parcours_id': 'PAR-01'})
ok(st == 201 and d.get('parcours_id') == 'PAR-01' and d.get('share_prompt') == PROMPT['share_prompt'] and d.get('token') and d['user']['email'] == em, 'nouveau créateur qui commence le parcours qu\'il a choisi : compte créé, connecté, et la question « Partager ? » est posée')
uid = d['user']['id']; ok(not posts(uid) and sql(f"SELECT COALESCE(auto_posts_optin, 'NULL') FROM users WHERE id = '{uid}'") == 'NULL' and row(uid) .startswith('active'), 'rien n\'est publié tant qu\'il n\'a pas répondu ; le parcours est bien actif')
st, d2, _ = call('POST', uid, '/auto-posts/first-answer', {'share': True, 'ref_type': 'parcours', 'ref_id': 'PAR-01', 'event': 'started'}); ok(st == 201 and d2['result'] == 'published' and len(posts(uid)) == 1, 'il répond « oui » : le démarrage du parcours est publié (vérifié côté serveur)')
st, d3, _ = call('POST', uid, '/parcours-inscription', {'name': 'Iris Insc', 'email': em, 'marque': 'Atelier Iris', 'craft': 'céramique', 'parcours_id': 'PAR-01'}); ok(st == 201 and 'share_prompt' not in d3 and len(posts(uid)) == 1, 'le créateur (connecté) rappelle avec sa propre adresse, même parcours : déjà commencé, aucune nouvelle question, aucune nouvelle publication')
st, d4, _ = call('POST', uid, '/parcours-inscription', {'name': 'Iris Insc', 'email': em, 'marque': 'Atelier Iris', 'craft': 'céramique', 'parcours_id': 'PAR-DOM-01'}); ok(st == 201 and 'share_prompt' not in d4 and len(posts(uid)) == 2 and sorted(p[1] for p in posts(uid)) == ['parcours_started', 'parcours_started'], 'un AUTRE parcours pour un créateur qui a déjà dit oui : publié directement, plus de question')
em2 = 'ps_insc2@example.test'; st, d5, _ = call('POST', None, '/parcours-inscription', {'name': 'Jo Insc', 'email': em2, 'marque': '', 'craft': '', 'parcours_id': 'PAR-01'}); uid2 = d5['user']['id']; call('POST', uid2, '/auto-posts/first-answer', {'share': False, 'ref_type': 'parcours', 'ref_id': 'PAR-01', 'event': 'started'})
st, d6, _ = call('POST', uid2, '/parcours-inscription', {'name': 'Jo Insc', 'email': em2, 'marque': '', 'craft': '', 'parcours_id': 'PAR-DOM-01'}); ok('share_prompt' not in d6 and not posts(uid2), 'un créateur qui a dit « non » : plus jamais de question, rien n\'est publié')
st, d7, _ = call('POST', None, '/parcours-inscription', {'name': 'Kim Insc', 'email': 'ps_insc3@example.test', 'parcours_id': 'PAR-INCONNU'}); ok(st == 201 and 'share_prompt' not in d7, 'un parcours inconnu du catalogue : aucune question')
ok(call('POST', None, '/parcours-inscription', {'name': 'X', 'email': 'pas-un-email'})[0] == 400 and call('GET', None, '/parcours-inscription')[0] == 405, 'les refus existants sont inchangés (adresse invalide 400, méthode GET 405)')

section("Ce qui n'est pas un démarrage par le créateur")
src_adm = open(os.path.join(ROOT, 'api', 'admin-suivi.php'), encoding='utf-8').read() + open(os.path.join(ROOT, 'api', 'admin-parcours.php'), encoding='utf-8').read()
ok('auto_post_hook' not in src_adm and 'parcours_start_paid' not in src_adm, 'une attribution par l\'administration (admin-suivi, admin-parcours) ne publie pas et ne pose pas la question : ce n\'est pas le créateur qui commence')
pay = open(os.path.join(ROOT, 'api', 'payment.php'), encoding='utf-8').read()
ok('parcours_start_paid(' in pay and "] + ($sharePrompt ?? []));" in pay and 'INSERT INTO user_parcours' not in pay and "$sharePrompt = null;" in pay, 'la confirmation de paiement utilise la fonction testée et renvoie share_prompt (le vrai appel Stripe n\'est pas rejouable ici : contrôle du code)')
ok(re.search(r"respond\(\[\s*'ok' => true,\s*'product_type'", pay) and pay.count('$sharePrompt') == 3, 'share_prompt est ajouté à la réponse de confirmation pour un parcours, jamais pour une candidature ni une prévente')

wipe()
summary()
