import os
import sys
from pathlib import Path

from fastapi.testclient import TestClient

# Ensure backend package on path
ROOT_DIR = Path(__file__).resolve().parent
if str(ROOT_DIR) not in sys.path:
    sys.path.insert(0, str(ROOT_DIR))

# Disable auth/rate limit for smoke
os.environ["DISABLE_AUTH"] = "true"
os.environ["REDIS_CACHE_TURN_ON"] = "false"

from server import app  # noqa: E402
from memos_core.db import DB_PATH, execute, init_memo_db  # noqa: E402


def setup_module(module=None):
    # Reset memo DB tables
    async def _reset():
        await init_memo_db()
        await execute("DELETE FROM memo_embeddings")
        await execute("DELETE FROM memos")

    import asyncio

    asyncio.run(_reset())


client = TestClient(app)


def test_history_endpoints():
    resp = client.get("/api/history/test-device")
    assert resp.status_code == 200
    resp = client.delete("/api/history/test-device")
    assert resp.status_code == 200


def test_system_prompt_get():
    resp = client.get("/api/agent/system-prompt")
    assert resp.status_code == 200
    data = resp.json()
    assert data.get("status") == "success"


def test_instance_and_auth_routes():
    # Instance info (GET + POST)
    resp = client.get("/api/v1/instance")
    assert resp.status_code == 200
    resp = client.post("/api/v1/instance")
    assert resp.status_code == 200

    # Instance patch
    resp = client.patch("/api/v1/instance", json={"data_dir": "data"})
    assert resp.status_code == 200

    # Instance setting
    resp = client.post("/api/v1/instance/setting")
    assert resp.status_code == 200

    # Auth
    resp = client.post("/api/v1/auth/signin", json={"email": "demo@example.com", "password": "pass"})
    assert resp.status_code == 200
    resp = client.post("/api/v1/auth/signup", json={"email": "demo@example.com", "password": "pass"})
    assert resp.status_code == 200
    resp = client.get("/api/v1/auth/me")
    assert resp.status_code == 200


def test_users_and_settings_routes():
    resp = client.get("/api/v1/users")
    assert resp.status_code == 200

    resp = client.post("/api/v1/users", json={"email": "demo@example.com", "password": "pass"})
    assert resp.status_code == 200
    user_id = resp.json().get("id", 1)

    resp = client.post("/api/v1/users/settings", json={})
    assert resp.status_code == 200

    resp = client.get(f"/api/v1/users/{user_id}")
    assert resp.status_code == 200

    resp = client.patch(f"/api/v1/users/{user_id}", json={"nickname": "demo"})
    assert resp.status_code == 200


def test_attachments_shortcuts_activities_idp():
    # Attachments list
    resp = client.get("/api/v1/attachments")
    assert resp.status_code == 200

    # Upload attachment
    resp = client.post(
        "/api/v1/attachments",
        files={"file": ("demo.txt", b"hello", "text/plain")},
    )
    assert resp.status_code == 200

    # Get attachment
    attachment_id = resp.json().get("id", 1)
    resp = client.get(f"/api/v1/attachments/{attachment_id}")
    assert resp.status_code == 200

    # Shortcuts list
    resp = client.get("/api/v1/shortcuts")
    assert resp.status_code == 200

    # Shortcuts create (POST path is overloaded; accept either)
    resp = client.post("/api/v1/shortcuts", json={"name": "demo", "filter": "tag:daily"})
    assert resp.status_code == 200

    # Shortcuts update/delete
    shortcut_id = resp.json().get("id", 1) if isinstance(resp.json(), dict) else 1
    resp = client.patch(f"/api/v1/shortcuts/{shortcut_id}", json={"name": "demo2"})
    assert resp.status_code == 200
    resp = client.delete(f"/api/v1/shortcuts/{shortcut_id}")
    assert resp.status_code == 200

    # Activities
    resp = client.get("/api/v1/activities")
    assert resp.status_code == 200

    # IDP list/create/update
    resp = client.get("/api/v1/idp")
    assert resp.status_code == 200
    resp = client.post("/api/v1/idp", json={"name": "demo", "type": "oidc"})
    assert resp.status_code == 200
    idp_id = resp.json().get("id", 1)
    resp = client.patch(f"/api/v1/idp/{idp_id}", json={"name": "demo2"})
    assert resp.status_code == 200


def test_memo_crud_and_embeddings():
    # Create memo
    memo_resp = client.post(
        "/api/v1/memos",
        json={"content": "smoke memo", "visibility": "PUBLIC", "tags": ["daily", "smoke"]},
    )
    assert memo_resp.status_code == 200
    memo_id = memo_resp.json()["id"]

    # List memos
    lst = client.get("/api/v1/memos")
    assert lst.status_code == 200
    assert any(m["id"] == memo_id for m in lst.json())

    # Get memo
    get_resp = client.get(f"/api/v1/memos/{memo_id}")
    assert get_resp.status_code == 200

    # Update memo
    patch_resp = client.patch(
        f"/api/v1/memos/{memo_id}", json={"content": "updated memo", "tags": ["daily"]}
    )
    assert patch_resp.status_code == 200
    assert patch_resp.json()["content"] == "updated memo"

    # Embedding create
    emb_resp = client.post(
        "/api/v1/memo-embeddings",
        json={
            "memoId": memo_id,
            "content": "updated memo",
            "tags": ["daily"],
            "dateKey": "2025-01-20",
            "embedding": [1.0, 0.0, 0.0],
            "model": "stub",
        },
    )
    assert emb_resp.status_code == 200

    # Embedding search
    search_resp = client.post(
        "/api/v1/memo-embeddings/search",
        json={"queryEmbedding": [1.0, 0.0, 0.0], "topK": 3},
    )
    assert search_resp.status_code == 200
    assert len(search_resp.json()) >= 1

    # Delete memo
    del_resp = client.delete(f"/api/v1/memos/{memo_id}")
    assert del_resp.status_code == 200
    assert del_resp.json()["status"] == "success"


# Note: /api/agent/chat is not exercised here because it triggers external LLM calls.
