# retoor <retoor@molodetz.nl>

import base64
import time
import requests
from tests.conftest import BASE_URL
from devplacepy.database import get_table
_counter_api_auth = [0]
def _signup_api_auth(password="secret123"):
    _counter_api_auth[0] += 1
    name = f"apiauth{int(time.time() * 1000)}{_counter_api_auth[0]}"
    email = f"{name}@t.dev"
    session = requests.Session()
    session.post(
        f"{BASE_URL}/auth/signup",
        data={
            "username": name,
            "email": email,
            "password": password,
            "confirm_password": password,
            "birth_date": "1990-01-01",
            "accept_terms": "1",
        },
        allow_redirects=True,
    )
    return session, name, email, password
def _user_api_auth(name):
    return get_table("users").find_one(username=name)
def _key_api_auth(name):
    return _user_api_auth(name)["api_key"]
import io
import uuid
from PIL import Image
JSON_media = {"Accept": "application/json"}
def _png_bytes_media(color=(200, 30, 30)):
    buf = io.BytesIO()
    Image.new("RGB", (8, 8), color).save(buf, "PNG")
    return buf.getvalue()
def _signup_media(prefix="media"):
    s = requests.Session()
    name = f"{prefix}_{uuid.uuid4().hex[:10]}"
    s.post(
        f"{BASE_URL}/auth/signup",
        data={
            "username": name,
            "email": f"{name}@test.devplace",
            "password": "secret123",
            "confirm_password": "secret123",
            "birth_date": "1990-01-01",
            "accept_terms": "1",
        },
        allow_redirects=True,
    )
    return s, name
def _login_media(seeded_db, who):
    s = requests.Session()
    creds = seeded_db[who]
    s.post(
        f"{BASE_URL}/auth/login",
        data={"email": creds["email"], "password": creds["password"]},
        allow_redirects=True,
    )
    return s
def _upload_media(s, name="pic.png", content=None, mime="image/png"):
    files = {"file": (name, content if content is not None else _png_bytes_media(), mime)}
    r = s.post(f"{BASE_URL}/uploads/upload", files=files)
    assert r.status_code == 201, r.text
    return r.json()["uid"]
def _create_post_media(s, attachment_uids, title="media post"):
    r = s.post(
        f"{BASE_URL}/posts/create",
        data={
            "content": "A post that carries media for the gallery tests.",
            "title": title,
            "topic": "random",
            "attachment_uids": attachment_uids,
        },
        allow_redirects=True,
    )
    assert r.status_code == 200, r.text[:300]
    assert "/posts/" in r.url, r.url
    return r.url
def _create_project_media(s, attachment_uids, title="Media Project"):
    r = s.post(
        f"{BASE_URL}/projects/create",
        data={
            "title": title,
            "description": "Project with media for gallery tests.",
            "project_type": "software",
            "platforms": "linux",
            "status": "In Development",
            "attachment_uids": attachment_uids,
        },
        allow_redirects=True,
    )
    assert r.status_code == 200, r.text[:300]
    assert "/projects/" in r.url, r.url
    return r.url
def _media_json(session, username):
    r = session.get(f"{BASE_URL}/profile/{username}?tab=media", headers=JSON_media)
    assert r.status_code == 200, r.text[:300]
    return r.json()
def _media_uids(session, username):
    return [m["uid"] for m in _media_json(session, username)["media"]]
def _seed_media_via_browser(page, title="ui media"):
    up = page.request.post(
        f"{BASE_URL}/uploads/upload",
        multipart={
            "file": {
                "name": "pic.png",
                "mimeType": "image/png",
                "buffer": _png_bytes_media(),
            }
        },
    )
    assert up.ok, up.text()
    uid = up.json()["uid"]
    post = page.request.post(
        f"{BASE_URL}/posts/create",
        form={
            "content": "media for the ui gallery test",
            "title": title,
            "topic": "random",
            "attachment_uids": uid,
        },
    )
    assert post.ok, post.text()
    return uid
def _media_uids_via_page(page, username):
    resp = page.request.get(f"{BASE_URL}/profile/{username}?tab=media", headers=JSON_media)
    return [m["uid"] for m in resp.json()["media"]]
from datetime import datetime, timedelta, timezone
from devplacepy.database import (
    get_table,
    get_activity_calendar,
    get_streaks,
    get_activity_heatmap,
    get_activity_months,
)
from devplacepy.utils import generate_uid, check_milestone_badges
_counter_streaks = [0]
def _make_user_streaks():
    _counter_streaks[0] += 1
    uid = generate_uid()
    name = f"stk{int(time.time() * 1000)}{_counter_streaks[0]}"
    get_table("users").insert(
        {
            "uid": uid,
            "username": name,
            "terms_version": "1",
            "email": f"{name}@t.dev",
            "role": "Member",
            "is_active": True,
            "xp": 0,
            "level": 1,
            "created_at": datetime.now(timezone.utc).isoformat(),
        }
    )
    return uid
def _insert_post(user_uid, dt):
    uid = generate_uid()
    get_table("posts").insert(
        {
            "deleted_at": None,
            "deleted_by": None,
            "uid": uid,
            "user_uid": user_uid,
            "slug": f"{uid[:8]}-streak",
            "title": None,
            "content": "streak activity",
            "topic": "random",
            "project_uid": None,
            "image": None,
            "stars": 0,
            "created_at": dt.isoformat(),
        }
    )
    return uid
def _insert_comment(user_uid, post_uid, dt):
    uid = generate_uid()
    get_table("comments").insert(
        {
            "deleted_at": None,
            "deleted_by": None,
            "uid": uid,
            "target_type": "post",
            "target_uid": post_uid,
            "post_uid": post_uid,
            "user_uid": user_uid,
            "content": "streak comment",
            "parent_uid": None,
            "created_at": dt.isoformat(),
        }
    )
    return uid


def test_owner_sees_own_key_on_profile(app_server):
    session, name, _, _ = _signup_api_auth()
    html = session.get(f"{BASE_URL}/profile/{name}").text
    assert "data-api-key-card" in html
    assert _key_api_auth(name) in html


def test_member_cannot_see_others_key(app_server):
    _signup_api_auth()  # absorb the admin slot if the DB is empty
    session_a, name_a, _, _ = _signup_api_auth()
    _, name_b, _, _ = _signup_api_auth()
    assert _user_api_auth(name_a)["role"] != "Admin"
    html = session_a.get(f"{BASE_URL}/profile/{name_b}").text
    assert "data-api-key-card" not in html


def test_media_tab_html_renders_grid(app_server):
    s, name = _signup_media()
    uid = _upload_media(s)
    _create_post_media(s, uid)
    r = s.get(f"{BASE_URL}/profile/{name}?tab=media")
    assert r.status_code == 200
    assert "media-grid" in r.text
    assert "data-lightbox" in r.text
    assert uid in r.text


def test_media_tab_empty_state_for_new_user(app_server):
    s, name = _signup_media()
    r = s.get(f"{BASE_URL}/profile/{name}?tab=media")
    assert r.status_code == 200
    assert "No media yet." in r.text
    assert _media_json(s, name)["media"] == []


def test_media_pagination(app_server):
    s, name = _signup_media()
    # per_page is 24; create 26 linked attachments
    for i in range(26):
        uid = _upload_media(s)
        _create_post_media(s, uid, title=f"p{i}")
    data = _media_json(s, name)
    pag = data["media_pagination"]
    assert pag["total"] >= 26
    assert pag["total_pages"] >= 2
    assert len(data["media"]) == pag["per_page"] == 24
    r2 = s.get(f"{BASE_URL}/profile/{name}?tab=media&page=2", headers=JSON_media)
    assert r2.status_code == 200
    assert len(r2.json()["media"]) >= 2
    # the HTML pager keeps the tab so links do not fall back to posts
    # (the ampersand is entity-escaped in the rendered href)
    html = s.get(f"{BASE_URL}/profile/{name}?tab=media").text
    assert "tab=media&amp;page=2" in html or "tab=media&page=2" in html


def test_profile_renders_heatmap_and_streak(app_server):
    _counter_streaks[0] += 1
    name = f"stkp{int(time.time() * 1000)}{_counter_streaks[0]}"
    s = requests.Session()
    s.post(
        f"{BASE_URL}/auth/signup",
        data={
            "username": name,
            "email": f"{name}@t.dev",
            "password": "secret123",
            "confirm_password": "secret123",
            "birth_date": "1990-01-01",
            "accept_terms": "1",
        },
        allow_redirects=True,
    )
    s.post(
        f"{BASE_URL}/posts/create",
        data={
            "content": "A post created today for the streak heatmap.",
            "title": "Streak heatmap post",
            "topic": "devlog",
        },
        allow_redirects=True,
    )
    html = s.get(f"{BASE_URL}/profile/{name}").text
    assert "heatmap-grid" in html
    assert "1 day streak" in html


def test_profile_badges_json_has_non_null_names(app_server):
    import time
    from devplacepy.database import get_table, refresh_snapshot
    from devplacepy.utils import BADGE_CATALOG, award_badge

    name = f"bdg{int(time.time() * 1000)}"
    session = requests.Session()
    session.post(
        f"{BASE_URL}/auth/signup",
        data={
            "username": name,
            "email": f"{name}@t.dev",
            "password": "secret123",
            "confirm_password": "secret123",
            "birth_date": "1990-01-01",
            "accept_terms": "1",
        },
        allow_redirects=True,
    )
    refresh_snapshot()
    user = get_table("users").find_one(username=name)
    assert user, f"user {name} not found after signup"
    award_badge(user["uid"], "First Post")
    award_badge(user["uid"], "Member")
    refresh_snapshot()
    r = session.get(
        f"{BASE_URL}/profile/{name}", headers={"Accept": "application/json"}
    )
    assert r.status_code == 200
    body = r.json()
    assert "badges" in body, "badges key missing from profile JSON"
    assert isinstance(body["badges"], list), "badges is not a list"
    assert len(body["badges"]) >= 2, f"expected at least 2 badges, got {len(body['badges'])}"
    for badge in body["badges"]:
        assert "name" in badge, f"badge missing name key: {badge}"
        assert badge["name"] is not None, f"badge name is null: {badge}"
        assert isinstance(badge["name"], str), f"badge name is not a string: {badge}"
        assert len(badge["name"]) > 0, f"badge name is empty: {badge}"
        assert "description" in badge, f"badge missing description key: {badge}"
        assert badge["description"] is not None, f"badge description is null: {badge}"
        assert isinstance(badge["description"], str), f"badge description is not a string: {badge}"
        assert len(badge["description"]) > 0, f"badge description is empty: {badge}"
        assert badge["description"] == BADGE_CATALOG[badge["name"]]["description"], (
            f"badge description mismatch: {badge['name']}"
        )




