import os
import pytest
from types import SimpleNamespace
import flaskr.dao as dao
import flaskr.service.config.funcs as config_funcs

_dummy_lock = SimpleNamespace(
    acquire=lambda *args, **kwargs: False, release=lambda *args, **kwargs: None
)


@pytest.mark.usefixtures("app")
class TestProfileRoutes:
    # Avoid real Redis in app init
    os.environ["REDIS_HOST"] = ""
    os.environ["REDIS_PORT"] = ""
    dao.init_redis = lambda _app: None  # type: ignore
    config_funcs.redis = SimpleNamespace(
        get=lambda _key: None,
        set=lambda *args, **kwargs: None,
        lock=lambda *args, **kwargs: _dummy_lock,
    )

    def _mock_request_user(self, monkeypatch):
        dummy_user = SimpleNamespace(user_id="test-user", language="en-US")
        monkeypatch.setattr(
            "flaskr.route.user.validate_user",
            lambda _app, _token: dummy_user,
            raising=False,
        )

    def test_hide_unused_profile_items_requires_parent(self, monkeypatch, test_client):
        self._mock_request_user(monkeypatch)
        resp = test_client.post("/api/profiles/hide-unused-profile-items", json={})
        payload = resp.get_json(force=True)
        assert resp.status_code == 200
        assert payload["code"] != 0

    def test_hide_unused_profile_items_ok(self, monkeypatch, test_client):
        called = {}

        def fake_hide(_app_ctx, parent_id, user_id):
            called["parent_id"] = parent_id
            called["user_id"] = user_id
            return [
                {
                    "profile_key": "k1",
                    "profile_scope": "user",
                    "profile_type": "text",
                    "profile_id": "pid",
                }
            ]

        monkeypatch.setattr(
            "flaskr.service.profile.routes.hide_unused_profile_items", fake_hide
        )
        self._mock_request_user(monkeypatch)

        resp = test_client.post(
            "/api/profiles/hide-unused-profile-items",
            json={"parent_id": "shifu_1"},
        )
        payload = resp.get_json(force=True)

        assert resp.status_code == 200
        assert payload["code"] == 0
        assert called["parent_id"] == "shifu_1"

    def test_update_profile_hidden_state_requires_parent(
        self, monkeypatch, test_client
    ):
        self._mock_request_user(monkeypatch)
        resp = test_client.post(
            "/api/profiles/update-profile-hidden-state",
            json={"profile_keys": ["k1"], "hidden": True},
        )
        payload = resp.get_json(force=True)
        assert resp.status_code == 200
        assert payload["code"] != 0

    def test_update_profile_hidden_state_ok(self, monkeypatch, test_client):
        called = {}

        def fake_update(_app_ctx, parent_id, profile_keys, hidden, user_id):
            called["parent_id"] = parent_id
            called["profile_keys"] = profile_keys
            called["hidden"] = hidden
            called["user_id"] = user_id
            return [
                {
                    "profile_key": "k1",
                    "profile_scope": "user",
                    "profile_type": "text",
                    "profile_id": "pid",
                    "is_hidden": int(hidden),
                }
            ]

        monkeypatch.setattr(
            "flaskr.service.profile.routes.update_profile_item_hidden_state",
            fake_update,
        )
        self._mock_request_user(monkeypatch)

        resp = test_client.post(
            "/api/profiles/update-profile-hidden-state",
            json={"parent_id": "shifu_1", "profile_keys": ["k1"], "hidden": True},
        )
        payload = resp.get_json(force=True)

        assert resp.status_code == 200
        assert payload["code"] == 0
        assert called["parent_id"] == "shifu_1"
        assert called["profile_keys"] == ["k1"]
        assert called["hidden"] is True

    def test_save_profile_item_only_supports_text_type(self, monkeypatch, test_client):
        self._mock_request_user(monkeypatch)

        resp = test_client.post(
            "/api/profiles/save-profile-item",
            json={
                "parent_id": "shifu_1",
                "profile_key": "nickname",
                "profile_type": "option",
            },
        )
        payload = resp.get_json(force=True)

        assert resp.status_code == 200
        assert payload["code"] != 0

    def test_save_profile_item_passes_only_active_fields(
        self, monkeypatch, test_client
    ):
        called = {}

        def fake_save(_app_ctx, profile_id, parent_id, user_id, key):
            called["profile_id"] = profile_id
            called["parent_id"] = parent_id
            called["user_id"] = user_id
            called["key"] = key
            return {
                "profile_key": key,
                "profile_scope": "user",
                "profile_type": "text",
                "profile_id": profile_id or "pid",
            }

        monkeypatch.setattr(
            "flaskr.service.profile.routes.save_profile_item", fake_save
        )
        self._mock_request_user(monkeypatch)

        resp = test_client.post(
            "/api/profiles/save-profile-item",
            json={
                "profile_id": "profile_1",
                "parent_id": "shifu_1",
                "profile_key": "nickname",
                "profile_type": "text",
                "profile_remark": "ignored",
                "profile_items": [{"name": "A", "value": "a"}],
            },
        )
        payload = resp.get_json(force=True)

        assert resp.status_code == 200
        assert payload["code"] == 0
        assert called == {
            "profile_id": "profile_1",
            "parent_id": "shifu_1",
            "user_id": "test-user",
            "key": "nickname",
        }
