"""profile 模块单测。"""

from __future__ import annotations

from pathlib import Path

import pytest


@pytest.fixture(autouse=True)
def tmp_db(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
    db_path = tmp_path / "xq.db"
    monkeypatch.setenv("XIANGQIN_DB_PATH", str(db_path))
    from xiangqin import db as db_module

    db_module.DEFAULT_DB_PATH = db_path
    db_module.init_db(db_path)
    yield db_path


@pytest.fixture()
def user_id():
    from xiangqin import auth

    r = auth.register("13800001111")
    v = auth.verify(r.request_id, "123456")
    return v.user_id


def test_fresh_profile_is_empty(user_id):
    from xiangqin import profile

    p = profile.get(user_id)
    assert p.gender is None
    assert p.age is None
    assert p.city is None
    assert p.tags == []
    assert p.bio is None


def test_update_happy(user_id):
    from xiangqin import profile

    p = profile.update(
        user_id,
        {
            "gender": "m",
            "age": 28,
            "city": "hangzhou",
            "tags": ["程序", "登山", "做饭"],
            "bio": "想找能一起爬山的人",
        },
    )
    assert p.gender == "m"
    assert p.age == 28
    assert p.city == "hangzhou"
    assert p.tags == ["程序", "登山", "做饭"]
    assert p.bio == "想找能一起爬山的人"


def test_tags_stored_as_pipe_wrapped(user_id):
    from xiangqin import db, profile

    profile.update(user_id, {"tags": ["登山", "做饭"]})
    with db.get_conn() as conn:
        raw = conn.execute("SELECT tags FROM profiles WHERE user_id = ?", (user_id,)).fetchone()[
            "tags"
        ]
    assert raw == "|登山|做饭|"


def test_tags_dedup(user_id):
    from xiangqin import profile

    p = profile.update(user_id, {"tags": ["登山", "登山", "做饭"]})
    assert p.tags == ["登山", "做饭"]


def test_gender_invalid(user_id):
    from xiangqin import profile

    with pytest.raises(profile.ProfileError) as e:
        profile.update(user_id, {"gender": "x"})
    assert e.value.code == "invalid_value"


def test_age_invalid(user_id):
    from xiangqin import profile

    with pytest.raises(profile.ProfileError) as e:
        profile.update(user_id, {"age": 15})
    assert e.value.code == "invalid_value"


def test_city_illegal_char(user_id):
    from xiangqin import profile

    with pytest.raises(profile.ProfileError) as e:
        profile.update(user_id, {"city": "hang/zhou"})
    assert e.value.code == "invalid_value"


def test_bio_too_long(user_id):
    from xiangqin import profile

    with pytest.raises(profile.ProfileError) as e:
        profile.update(user_id, {"bio": "x" * 501})
    assert e.value.code == "invalid_value"


def test_tags_too_many(user_id):
    from xiangqin import profile

    with pytest.raises(profile.ProfileError) as e:
        profile.update(user_id, {"tags": [f"t{i}" for i in range(21)]})
    assert e.value.code == "invalid_value"


def test_partial_update_preserves_other_fields(user_id):
    from xiangqin import profile

    profile.update(user_id, {"gender": "m", "age": 28, "city": "hangzhou"})
    profile.update(user_id, {"bio": "hello"})
    p = profile.get(user_id)
    assert p.gender == "m"
    assert p.age == 28
    assert p.city == "hangzhou"
    assert p.bio == "hello"


def test_clear_tags(user_id):
    from xiangqin import profile

    profile.update(user_id, {"tags": ["登山"]})
    p = profile.update(user_id, {"tags": []})
    assert p.tags == []


def test_no_fields_to_update(user_id):
    from xiangqin import profile

    with pytest.raises(profile.ProfileError) as e:
        profile.update(user_id, {})
    assert e.value.code == "invalid_value"
