"""Ziyaretçi hafızası testleri — identify, returning, merge, forget, izolasyon, memory."""
import uuid

import pytest

from app.models.visitor import FlovyVisitor
from app.services.visitor.fingerprint import compute_fingerprint, detect_device_type
from app.services.visitor.memory_builder import MemoryBuilder
from tests.conftest import unique_email


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


async def _make_widget(client, headers) -> dict:
    r = await client.post("/api/widgets", headers=headers, json={"name": "Ana Site"})
    return r.json()["data"]


# ============================================================
# IDENTIFY
# ============================================================


@pytest.mark.asyncio
async def test_identify_new_then_returning(client):
    h = await _auth_headers(client)
    w = await _make_widget(client, h)
    key = w["api_key"]
    vuuid = uuid.uuid4().hex

    r1 = await client.post(
        f"/api/widget/{key}/visitor/identify", json={"visitor_uuid": vuuid}
    )
    assert r1.status_code == 200
    vid = r1.json()["data"]["visitor_id"]
    assert r1.json()["data"]["is_returning"] is False

    # aynı uuid → aynı kayıt
    r2 = await client.post(
        f"/api/widget/{key}/visitor/identify", json={"visitor_uuid": vuuid}
    )
    assert r2.json()["data"]["visitor_id"] == vid


@pytest.mark.asyncio
async def test_returning_after_second_session(client):
    h = await _auth_headers(client)
    w = await _make_widget(client, h)
    key = w["api_key"]
    vuuid = uuid.uuid4().hex

    # iki ayrı sohbet aç → ikinci ziyaret returning olmalı
    await client.post(f"/api/widget/{key}/session/create", json={"visitor_uuid": vuuid})
    await client.post(f"/api/widget/{key}/session/create", json={"visitor_uuid": vuuid})

    ident = await client.post(
        f"/api/widget/{key}/visitor/identify", json={"visitor_uuid": vuuid}
    )
    assert ident.json()["data"]["is_returning"] is True


@pytest.mark.asyncio
async def test_session_links_visitor(client):
    h = await _auth_headers(client)
    w = await _make_widget(client, h)
    vuuid = uuid.uuid4().hex
    await client.post(
        f"/api/widget/{w['api_key']}/session/create", json={"visitor_uuid": vuuid}
    )
    # panel oturum listesinde visitor bağlı (profil panelden çekilebilir)
    ident = await client.post(
        f"/api/widget/{w['api_key']}/visitor/identify", json={"visitor_uuid": vuuid}
    )
    vid = ident.json()["data"]["visitor_id"]
    prof = await client.get(f"/api/visitors/{vid}", headers=h)
    assert prof.status_code == 200
    assert prof.json()["data"]["total_sessions"] >= 1


# ============================================================
# MERGE / CONTACT
# ============================================================


@pytest.mark.asyncio
async def test_contact_requires_kvkk_consent(client):
    h = await _auth_headers(client)
    w = await _make_widget(client, h)
    key = w["api_key"]
    vuuid = uuid.uuid4().hex
    vid = (await client.post(
        f"/api/widget/{key}/visitor/identify", json={"visitor_uuid": vuuid}
    )).json()["data"]["visitor_id"]

    # onay yok → 422
    bad = await client.post(
        f"/api/widget/{key}/visitor/{vid}/contact",
        json={"email": "a@example.com", "kvkk_consent": False},
    )
    assert bad.status_code == 422

    ok_ = await client.post(
        f"/api/widget/{key}/visitor/{vid}/contact",
        json={"email": "ayse@example.com", "name": "Ayşe", "kvkk_consent": True},
    )
    assert ok_.status_code == 200
    assert ok_.json()["data"]["email"] == "ayse@example.com"


@pytest.mark.asyncio
async def test_merge_two_anonymous_profiles(client):
    h = await _auth_headers(client)
    w = await _make_widget(client, h)
    key = w["api_key"]

    # iki anonim profil, ikisi de aynı email ile contact verir
    v1 = (await client.post(
        f"/api/widget/{key}/visitor/identify", json={"visitor_uuid": uuid.uuid4().hex}
    )).json()["data"]["visitor_id"]
    v2 = (await client.post(
        f"/api/widget/{key}/visitor/identify", json={"visitor_uuid": uuid.uuid4().hex}
    )).json()["data"]["visitor_id"]
    assert v1 != v2

    email = "merge@example.com"
    await client.post(
        f"/api/widget/{key}/visitor/{v1}/contact",
        json={"email": email, "kvkk_consent": True},
    )
    # v2 aynı email → v1 ile merge, v2 hedefte kalır, v1 silinir
    await client.post(
        f"/api/widget/{key}/visitor/{v2}/contact",
        json={"email": email, "kvkk_consent": True},
    )

    # v1 artık yok (kaynak silindi)
    assert (await client.get(f"/api/visitors/{v1}", headers=h)).status_code == 404
    assert (await client.get(f"/api/visitors/{v2}", headers=h)).status_code == 200


# ============================================================
# FORGET (KVKK "verimi sil")
# ============================================================


@pytest.mark.asyncio
async def test_forget_anonymizes_pii(client):
    h = await _auth_headers(client)
    w = await _make_widget(client, h)
    key = w["api_key"]
    vid = (await client.post(
        f"/api/widget/{key}/visitor/identify", json={"visitor_uuid": uuid.uuid4().hex}
    )).json()["data"]["visitor_id"]
    await client.post(
        f"/api/widget/{key}/visitor/{vid}/contact",
        json={"email": "del@example.com", "name": "Sil", "kvkk_consent": True},
    )

    f = await client.post(f"/api/widget/{key}/visitor/{vid}/forget")
    assert f.status_code == 204

    g = await client.get(f"/api/visitors/{vid}", headers=h)
    data = g.json()["data"]
    assert data["email"] is None
    assert data["name"] is None
    assert data["anonymized_at"] is not None


# ============================================================
# TENANT İZOLASYONU
# ============================================================


@pytest.mark.asyncio
async def test_visitor_tenant_isolation(client):
    h_a = await _auth_headers(client)
    h_b = await _auth_headers(client)
    w = await _make_widget(client, h_a)
    vid = (await client.post(
        f"/api/widget/{w['api_key']}/visitor/identify", json={"visitor_uuid": uuid.uuid4().hex}
    )).json()["data"]["visitor_id"]

    # B tenant A'nın ziyaretçisini göremez
    assert (await client.get(f"/api/visitors/{vid}", headers=h_b)).status_code == 404


# ============================================================
# MEMORY BUILDER (saf birim test)
# ============================================================


def test_memory_builder_no_consent_returns_empty():
    v = FlovyVisitor(
        tenant_id="t", visitor_uuid="u", is_returning=True, kvkk_consent_at=None,
        name="Ali",
    )
    assert MemoryBuilder().build(v) == ""


def test_memory_builder_builds_context():
    from datetime import datetime

    v = FlovyVisitor(
        tenant_id="t",
        visitor_uuid="u",
        is_returning=True,
        kvkk_consent_at=datetime(2026, 1, 1),
        name="Ayşe",
        products_viewed=[{"id": "1", "title": "Collagen Plus"}],
        products_purchased=[{"id": "2", "title": "Vitamin C"}],
        last_intent="fiyat",
    )
    out = MemoryBuilder().build(v)
    assert "Ayşe" in out
    assert "Collagen Plus" in out
    assert "Vitamin C" in out
    assert "fiyat" in out


def test_fingerprint_helpers():
    h1 = compute_fingerprint({"canvas": "x", "screen": "1920x1080"})
    h2 = compute_fingerprint({"screen": "1920x1080", "canvas": "x"})
    assert h1 == h2  # sıra bağımsız
    assert compute_fingerprint(None) is None
    assert detect_device_type("Mozilla/5.0 (iPhone)") == "mobile"
    assert detect_device_type("Mozilla/5.0 (Macintosh)") == "desktop"
