"""Ürün + kategori testleri — CRUD, stok durumu, varyant, tenant izolasyonu."""
import pytest

from tests.conftest import unique_email


async def _auth_headers(client) -> dict:
    email = unique_email()
    r = await client.post(
        "/api/auth/register",
        json={"name": "Shop", "email": email, "password": "secret123"},
    )
    token = r.json()["data"]["token"]["access_token"]
    return {"Authorization": f"Bearer {token}"}


@pytest.mark.asyncio
async def test_create_and_get_product(client):
    h = await _auth_headers(client)
    r = await client.post(
        "/api/products",
        headers=h,
        json={"title": "Collagen Plus", "price": "299.90", "stock_quantity": 50},
    )
    assert r.status_code == 201
    data = r.json()["data"]
    assert data["title"] == "Collagen Plus"
    assert data["stock_status"] == "in_stock"
    assert data["embedding_status"] == "pending"
    pid = data["id"]

    g = await client.get(f"/api/products/{pid}", headers=h)
    assert g.status_code == 200
    assert g.json()["data"]["id"] == pid


@pytest.mark.asyncio
async def test_stock_status_computed(client):
    h = await _auth_headers(client)
    # 0 → out_of_stock
    r1 = await client.post(
        "/api/products", headers=h,
        json={"title": "A", "price": "10", "stock_quantity": 0},
    )
    assert r1.json()["data"]["stock_status"] == "out_of_stock"
    # <= threshold → low
    r2 = await client.post(
        "/api/products", headers=h,
        json={"title": "B", "price": "10", "stock_quantity": 3, "low_stock_threshold": 5},
    )
    assert r2.json()["data"]["stock_status"] == "low"


@pytest.mark.asyncio
async def test_create_product_with_variants(client):
    h = await _auth_headers(client)
    r = await client.post(
        "/api/products",
        headers=h,
        json={
            "title": "Tişört",
            "price": "199",
            "variants": [
                {"title": "Kırmızı / L", "price": "199", "stock_quantity": 5,
                 "attributes": {"renk": "kırmızı", "beden": "L"}},
                {"title": "Mavi / M", "price": "199", "stock_quantity": 2},
            ],
        },
    )
    assert r.status_code == 201
    variants = r.json()["data"]["variants"]
    assert len(variants) == 2
    titles = {v["title"] for v in variants}
    assert "Kırmızı / L" in titles


@pytest.mark.asyncio
async def test_update_product_resets_embedding(client):
    h = await _auth_headers(client)
    pid = (await client.post(
        "/api/products", headers=h, json={"title": "X", "price": "10"}
    )).json()["data"]["id"]

    upd = await client.put(
        f"/api/products/{pid}", headers=h, json={"title": "X Yeni", "stock_quantity": 0}
    )
    assert upd.status_code == 200
    body = upd.json()["data"]
    assert body["title"] == "X Yeni"
    assert body["stock_status"] == "out_of_stock"
    assert body["embedding_status"] == "pending"


@pytest.mark.asyncio
async def test_soft_delete_then_404(client):
    h = await _auth_headers(client)
    pid = (await client.post(
        "/api/products", headers=h, json={"title": "Sil", "price": "10"}
    )).json()["data"]["id"]

    d = await client.delete(f"/api/products/{pid}", headers=h)
    assert d.status_code == 204
    g = await client.get(f"/api/products/{pid}", headers=h)
    assert g.status_code == 404
    assert g.json()["error"]["code"] == "NOT_FOUND"


@pytest.mark.asyncio
async def test_list_pagination(client):
    h = await _auth_headers(client)
    for i in range(5):
        await client.post("/api/products", headers=h, json={"title": f"P{i}", "price": "1"})

    r = await client.get("/api/products?limit=2", headers=h)
    assert r.status_code == 200
    assert len(r.json()["data"]) == 2
    assert r.json()["meta"]["has_more"] is True
    cursor = r.json()["meta"]["next_cursor"]

    r2 = await client.get(f"/api/products?limit=2&cursor={cursor}", headers=h)
    assert len(r2.json()["data"]) == 2
    # sayfa çakışması olmamalı
    ids1 = {p["id"] for p in r.json()["data"]}
    ids2 = {p["id"] for p in r2.json()["data"]}
    assert ids1.isdisjoint(ids2)


@pytest.mark.asyncio
async def test_tenant_isolation(client):
    h_a = await _auth_headers(client)
    h_b = await _auth_headers(client)
    pid = (await client.post(
        "/api/products", headers=h_a, json={"title": "Gizli", "price": "10"}
    )).json()["data"]["id"]

    # B tenant A'nın ürününü göremez
    g = await client.get(f"/api/products/{pid}", headers=h_b)
    assert g.status_code == 404
    # B'nin listesi boş
    lst = await client.get("/api/products", headers=h_b)
    assert lst.json()["data"] == []


@pytest.mark.asyncio
async def test_product_requires_auth(client):
    r = await client.get("/api/products")
    assert r.status_code == 401


# ============================================================
# CATEGORIES
# ============================================================


@pytest.mark.asyncio
async def test_category_crud_and_slug_conflict(client):
    h = await _auth_headers(client)
    r = await client.post(
        "/api/products/categories", headers=h,
        json={"name": "Takviye", "slug": "takviye"},
    )
    assert r.status_code == 201
    cid = r.json()["data"]["id"]

    # aynı slug → 409
    dup = await client.post(
        "/api/products/categories", headers=h,
        json={"name": "Takviye 2", "slug": "takviye"},
    )
    assert dup.status_code == 409

    lst = await client.get("/api/products/categories", headers=h)
    assert any(c["id"] == cid for c in lst.json()["data"])

    upd = await client.put(
        f"/api/products/categories/{cid}", headers=h, json={"name": "Yeni Ad"}
    )
    assert upd.json()["data"]["name"] == "Yeni Ad"

    d = await client.delete(f"/api/products/categories/{cid}", headers=h)
    assert d.status_code == 204


@pytest.mark.asyncio
async def test_category_self_parent_rejected(client):
    h = await _auth_headers(client)
    cid = (await client.post(
        "/api/products/categories", headers=h, json={"name": "A", "slug": "a"}
    )).json()["data"]["id"]
    r = await client.put(
        f"/api/products/categories/{cid}", headers=h, json={"parent_id": cid}
    )
    assert r.status_code == 422
    assert r.json()["error"]["code"] == "VALIDATION_FAILED"
