"""Utilitaires des tests du serveur (PHP + MariaDB réels). Voir tests/README.md."""
import json, os, shutil, subprocess, sys, tempfile, urllib.error, urllib.request
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
API = os.environ.get('ULUANA_TEST_API', 'http://127.0.0.1:8084/api')
DB = os.environ.get('ULUANA_TEST_DB', 'uluana_test')
SQL_CMD = os.environ.get('ULUANA_TEST_SQL_CMD', 'mariadb -uroot').split()
if 'test' not in DB: sys.exit(f"REFUS : la base « {DB} » ne contient pas « test » dans son nom. Ces tests effacent des donnees.")
_tok = {}
n = {'p': 0, 'f': 0}

def sql(q):
    return subprocess.check_output(SQL_CMD + ['--default-character-set=utf8mb4', DB, '-N', '-B', '-r', '-e', q]).decode().strip()

def reset_rate_limits():
    """Repart d'un compteur de limitation de debit vide (api/_core.php, rate_limit() : fichiers dans le dossier temporaire). A appeler au debut d'une suite qui enchaine beaucoup d'ecritures, sinon deux lancements dans la meme minute se bloquent mutuellement."""
    shutil.rmtree(os.path.join(tempfile.gettempdir(), 'uluana_rl'), ignore_errors=True)

def tok(user_id):
    if user_id not in _tok:
        code = '$_SERVER["HTTP_HOST"]="dev-api.uluana.art"; ob_start(); require ' + json.dumps(ROOT + '/api/_core.php') + '; ob_end_clean(); echo jwt_issue(["id"=>$argv[1]]);'
        _tok[user_id] = subprocess.check_output(['php', '-r', code, user_id], stderr=subprocess.DEVNULL).decode().strip().splitlines()[-1]
    return _tok[user_id]

def call(method, who, path, body=None, raw=None, headers=None):
    """→ (statut, JSON, en-têtes). `raw` : corps envoyé tel quel (pour tester un JSON invalide)."""
    h = {'Host': 'dev-api.uluana.art', 'Content-Type': 'application/json'}
    if who: h['Authorization'] = 'Bearer ' + tok(who)
    h.update(headers or {})
    data = raw if raw is not None else (json.dumps(body).encode() if body is not None else None)
    req = urllib.request.Request(API + path, method=method, data=data, headers=h)
    try:
        with urllib.request.urlopen(req, timeout=30) as r: return r.status, json.loads(r.read() or b'{}'), dict(r.headers)
    except urllib.error.HTTPError as e:
        b = e.read(); return e.code, (json.loads(b) if b else {}), dict(e.headers)

def ok(cond, msg):
    n['p'] += bool(cond); n['f'] += (not cond)
    print(('  OK  ' if cond else '  KO  ') + msg)

def mk_user(uid, role='prospect', first='Test', last=''):
    sql(f"INSERT INTO users (id,email,role,firstname,lastname,craft,active,is_test) VALUES ('{uid}','{uid}@test.test','{role}','{first}','{last or uid}','',1,0)")

def summary():
    print(f"\n{'✔' if n['f'] == 0 else '✘'} {n['p']} vérifications OK, {n['f']} en échec")
    sys.exit(1 if n['f'] else 0)

def reset_themes():
    """Remet les thèmes de publication à l'état de départ : les 6 thèmes amorcés par 2026_10_13_001 (qui ne les insère QUE si la table est vide), puis le thème réservé « Avancées »
    (2026_10_27_001). À utiliser à la place de « DELETE FROM post_themes » : un test qui vide les thèmes sans remettre le thème réservé priverait les autres suites de leurs thèmes."""
    sql("DELETE FROM post_themes")
    sql(open(ROOT + '/sql/2026_10_13_001_messaging_settings.sql', encoding='utf-8').read())
    m = open(ROOT + '/sql/2026_10_27_001_auto_posts.sql', encoding='utf-8').read(); i = m.index("INSERT INTO post_themes"); sql(m[i:m.index(';', i) + 1])
