# retoor <retoor@molodetz.nl>

import io
import uuid
import requests
from PIL import Image
from tests.conftest import BASE_URL
from devplacepy.database import get_table
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"]]


def test_member_media_schema_hides_soft_delete():
    from devplacepy.schemas import MediaItemOut, AdminMediaItemOut

    assert "deleted_at" not in MediaItemOut.model_fields
    # the admin-only model is the only one that exposes it
    assert "deleted_at" in AdminMediaItemOut.model_fields
    assert "uploader" in AdminMediaItemOut.model_fields


def test_devii_delete_media_is_confirm_gated():
    from devplacepy.services.devii.actions.catalog import ACTIONS
    from devplacepy.services.devii.actions.dispatcher import (
        CONFIRM_REQUIRED,
        confirmation_error,
    )

    names = {a.name for a in ACTIONS}
    assert "delete_media" in names
    assert "list_media" in names
    assert "delete_media" in CONFIRM_REQUIRED
    # without confirm the dispatcher refuses; with confirm it proceeds
    assert confirmation_error("delete_media", {}) is not None
    assert confirmation_error("delete_media", {"confirm": "true"}) is None
    # delete tools state the soft-delete + confirmation contract, matching the
    # convention shared by delete_post/comment/gist/project/file/news.
    delete = next(a for a in ACTIONS if a.name == "delete_media")
    blob = f"{delete.summary} {delete.description or ''}".lower()
    assert "soft delete" in blob
    assert "confirm" in blob


def test_admin_report_subject_is_the_redacted_admin_user_model():
    from devplacepy.schemas import AdminReportOut, AdminUserOut

    annotation = AdminReportOut.model_fields["subject"].annotation
    assert AdminUserOut in getattr(annotation, "__args__", (annotation,))
    assert "password_hash" not in AdminUserOut.model_fields
    assert "api_key" not in AdminUserOut.model_fields


def test_accept_terms_page_reports_versions_not_consents():
    from devplacepy.schemas import AcceptTermsOut

    assert set(AcceptTermsOut.model_fields) == {"terms_version", "accepted_version"}
    assert "consents" not in AcceptTermsOut.model_fields


def test_the_workspace_index_row_carries_its_uid_and_owner():
    from devplacepy.schemas import WorkspaceIndexItemOut

    for field in ("uid", "owner_uid", "description", "project_url"):
        assert field in WorkspaceIndexItemOut.model_fields


def test_devii_reads_the_account_deletion_page_before_deleting():
    from devplacepy.services.devii.actions.catalog import ACTIONS
    from devplacepy.services.devii.actions.dispatcher import (
        CONFIRM_REQUIRED,
        confirmation_error,
    )

    by_name = {action.name: action for action in ACTIONS}
    reader = by_name["view_account_deletion"]
    assert reader.method == "GET"
    assert reader.path == "/profile/{username}/delete"
    assert "view_account_deletion" not in CONFIRM_REQUIRED
    assert "delete_my_account" in CONFIRM_REQUIRED
    assert confirmation_error("delete_my_account", {}) is not None
    assert confirmation_error("delete_my_account", {"confirm": "true"}) is None
    assert any(param.name == "confirm" for param in by_name["delete_my_account"].params)


def test_game_legacy_out_defaults():
    from devplacepy.schemas import GameLegacyOut

    out = GameLegacyOut(key="multiplier", name="Tech Debt Payoff", level=2, cost=5)
    dumped = out.model_dump()
    assert dumped["key"] == "multiplier"
    assert dumped["level"] == 2
    assert dumped["cost"] == 5
    assert dumped["maxed"] is False


def test_game_farm_out_exposes_stars_and_legacy():
    from devplacepy.schemas import GameFarmOut, GameLegacyOut

    farm = GameFarmOut(
        stars=7,
        steal_cooldown_seconds=120,
        legacy=[GameLegacyOut(key="speed", level=1)],
    )
    dumped = farm.model_dump()
    assert dumped["stars"] == 7
    assert dumped["steal_cooldown_seconds"] == 120
    assert dumped["legacy"][0]["key"] == "speed"


def test_game_plot_out_steal_and_golden_fields():
    from devplacepy.schemas import GamePlotOut

    plot = GamePlotOut(
        slot=0,
        can_steal=True,
        steal_coins=40,
        steal_cooldown_seconds=600,
        steal_reason="protected",
        is_golden=True,
    )
    dumped = plot.model_dump()
    assert dumped["steal_cooldown_seconds"] == 600
    assert dumped["steal_reason"] == "protected"
    assert dumped["is_golden"] is True
