"""Ad-hoc HTTP test for the ticket checklist + per-user draft features.

Run against the live dev server (http://127.0.0.1:5000) as admin@local.test
(tenant_internal). Exercises real routes through the full CSRF + auth stack.

    venv/bin/python tests/manual_checklist_draft_test.py

Exit code 0 = all pass, 1 = a failure (details printed).
"""
import os
import re
import sys

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import requests
from sqlalchemy import create_engine, text

from supporthub.app.config import config

BASE = "http://127.0.0.1:5000"
EMAIL = "admin@local.test"
PASSWORD = "Admin123!ChangeMe"

class InsecureCookieSession(requests.Session):
    """A requests session that re-sends Secure cookies over plain HTTP.

    The prod server sets SECURE_COOKIES=true, so its session cookie carries the
    Secure flag. We test it directly over http://127.0.0.1 (Caddy normally
    terminates TLS), where `requests` would otherwise refuse to resend the
    cookie and every authenticated call would 400 on CSRF. Stripping the Secure
    flag from the jar after each response keeps the session usable locally.
    """
    def request(self, *args, **kwargs):
        resp = super().request(*args, **kwargs)
        for c in self.cookies:
            c.secure = False
        return resp


results = []
def check(name, ok, detail=""):
    results.append((name, ok, detail))
    print(f"[{'PASS' if ok else 'FAIL'}] {name}" + (f" — {detail}" if detail else ""))


def get_ticket_id():
    eng = create_engine(config.database_url())
    with eng.connect() as c:
        c.execute(text("SET search_path TO tenant_internal, public"))
        tid = c.execute(text("select id from tenant_internal.tickets order by id limit 1")).scalar()
    return tid


def extract_csrf(html):
    # Try hidden form field first, then the meta tag.
    m = re.search(r'name="csrf_token"[^>]*value="([^"]+)"', html)
    if m:
        return m.group(1)
    m = re.search(r'<meta name="csrf-token" content="([^"]+)"', html)
    return m.group(1) if m else None


def login(s):
    r = s.get(f"{BASE}/login", timeout=10)
    token = extract_csrf(r.text)
    r = s.post(f"{BASE}/login",
               data={"username": EMAIL, "password": PASSWORD, "csrf_token": token},
               allow_redirects=False, timeout=10)
    return r.status_code in (302, 303)


def meta_csrf(s):
    # Pull a fresh CSRF token from any authenticated page (the ticket page meta tag).
    r = s.get(f"{BASE}/", timeout=10)
    return extract_csrf(r.text)


def main():
    tid = get_ticket_id()
    if not tid:
        check("precondition: a ticket exists in tenant_internal", False)
        return finish()
    print(f"Using ticket id {tid}\n")

    s = InsecureCookieSession()

    if not login(s):
        check("login as admin@local.test", False)
        return finish()
    check("login as admin@local.test", True)

    csrf = meta_csrf(s)
    check("got CSRF token from authenticated page", bool(csrf))
    H = {"Content-Type": "application/json", "X-CSRFToken": csrf or "",
         "X-Requested-With": "XMLHttpRequest"}

    # ---------- PER-USER DRAFT (#3) ----------
    # CSRF must be enforced: POST without the token → 400.
    r = s.post(f"{BASE}/ticket/{tid}/draft", json={"html": "<p>x</p>"},
               headers={"Content-Type": "application/json"}, timeout=10)
    check("draft POST without CSRF is rejected (400)", r.status_code == 400, f"got {r.status_code}")

    # With token → 204, then GET round-trips the value.
    r = s.post(f"{BASE}/ticket/{tid}/draft", json={"html": "<p>draft A</p>"}, headers=H, timeout=10)
    check("draft POST with CSRF saves (204)", r.status_code == 204, f"got {r.status_code}")
    r = s.get(f"{BASE}/ticket/{tid}/draft", timeout=10)
    check("draft GET returns saved html", r.json().get("html") == "<p>draft A</p>", f"got {r.json()}")

    # Stored per-user in ticket_drafts under user_id=1 (the admin/owner).
    eng = create_engine(config.database_url())
    with eng.connect() as c:
        c.execute(text("SET search_path TO tenant_internal, public"))
        row = c.execute(text("select user_id, body_html from tenant_internal.ticket_drafts where ticket_id=:t"),
                        {"t": tid}).fetchall()
    check("draft stored per-user in ticket_drafts", len(row) == 1 and row[0][0] == 1, f"rows={row}")

    # Clearing (html null) deletes the row.
    r = s.post(f"{BASE}/ticket/{tid}/draft", json={"html": None}, headers=H, timeout=10)
    check("draft clear (null) returns 204", r.status_code == 204, f"got {r.status_code}")
    r = s.get(f"{BASE}/ticket/{tid}/draft", timeout=10)
    check("draft GET returns null after clear", r.json().get("html") is None, f"got {r.json()}")

    # ---------- CHECKLIST (#2) ----------
    r = s.get(f"{BASE}/ticket/{tid}/checklist", timeout=10)
    check("checklist GET returns items list", r.status_code == 200 and "items" in r.json(), f"got {r.status_code}")

    r = s.post(f"{BASE}/ticket/{tid}/checklist", json={"text": "Verify refund processed"}, headers=H, timeout=10)
    ok = r.status_code == 201 and r.json().get("text") == "Verify refund processed" and r.json().get("source") == "manual"
    check("checklist POST adds manual item (201)", ok, f"got {r.status_code} {r.text[:120]}")
    item_id = r.json().get("id") if r.status_code == 201 else None

    r = s.get(f"{BASE}/ticket/{tid}/checklist", timeout=10)
    ids = [i["id"] for i in r.json().get("items", [])]
    check("checklist GET includes new item", item_id in ids, f"ids={ids}")

    r = s.patch(f"{BASE}/ticket/{tid}/checklist/{item_id}", json={"done": True}, headers=H, timeout=10)
    check("checklist PATCH marks done", r.status_code == 200 and r.json().get("done") is True, f"got {r.status_code} {r.text[:120]}")

    # empty add is rejected
    r = s.post(f"{BASE}/ticket/{tid}/checklist", json={"text": "   "}, headers=H, timeout=10)
    check("checklist POST rejects empty text (400)", r.status_code == 400, f"got {r.status_code}")

    r = s.delete(f"{BASE}/ticket/{tid}/checklist/{item_id}", headers=H, timeout=10)
    check("checklist DELETE returns 204", r.status_code == 204, f"got {r.status_code}")
    r = s.get(f"{BASE}/ticket/{tid}/checklist", timeout=10)
    ids = [i["id"] for i in r.json().get("items", [])]
    check("checklist item gone after delete", item_id not in ids, f"ids={ids}")

    return finish()


def finish():
    n = len(results); passed = sum(1 for _, ok, _ in results if ok)
    print(f"\n{'='*40}\n{passed}/{n} checks passed")
    failed = [name for name, ok, _ in results if not ok]
    if failed:
        print("FAILED:", ", ".join(failed))
        sys.exit(1)
    print("ALL GREEN")
    sys.exit(0)


if __name__ == "__main__":
    main()
