from fastapi.testclient import TestClient

from zbt.core.config import Settings
from zbt.domains.identity.repository import InMemoryIdentityRepository
from zbt.main import create_app


def test_h5_user_can_login_with_development_otp_and_read_profile() -> None:
    settings = Settings(
        app_env="test",
        jwt_access_secret="a" * 32,
        jwt_refresh_secret="b" * 32,
        field_encryption_key="c" * 32,
        dev_fixed_otp="147258",
    )
    app = create_app(
        settings=settings,
        identity_repository=InMemoryIdentityRepository(),
    )

    with TestClient(app) as client:
        code_response = client.post(
            "/api/v1/h5/auth/request-code",
            json={"mobile": "18800000001"},
        )
        assert code_response.status_code == 200
        assert code_response.json()["data"] == {"expires_in": 300}

        login_response = client.post(
            "/api/v1/h5/auth/login",
            json={"mobile": "18800000001", "code": "147258"},
        )
        assert login_response.status_code == 200
        assert login_response.json()["data"]["user"]["mobile"] == "18800000001"
        tokens = login_response.json()["data"]["tokens"]

        profile_response = client.get(
            "/api/v1/h5/me",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
        )
        assert profile_response.status_code == 200
        assert profile_response.json()["data"]["mobile_masked"] == "188****0001"


def test_refresh_token_is_rotated_and_cannot_be_reused() -> None:
    settings = Settings(
        app_env="test",
        jwt_access_secret="a" * 32,
        jwt_refresh_secret="b" * 32,
        field_encryption_key="c" * 32,
        dev_fixed_otp="147258",
    )
    app = create_app(
        settings=settings,
        identity_repository=InMemoryIdentityRepository(),
    )

    with TestClient(app) as client:
        login = client.post(
            "/api/v1/h5/auth/login",
            json={"mobile": "18800000001", "code": "147258"},
        ).json()["data"]["tokens"]

        refreshed = client.post(
            "/api/v1/h5/auth/refresh",
            json={"refresh_token": login["refresh_token"]},
        )
        assert refreshed.status_code == 200
        next_tokens = refreshed.json()["data"]["tokens"]
        assert next_tokens["refresh_token"] != login["refresh_token"]

        reused = client.post(
            "/api/v1/h5/auth/refresh",
            json={"refresh_token": login["refresh_token"]},
        )
        assert reused.status_code == 401
        assert reused.json()["error"]["code"] == "AUTH_REQUIRED"


def test_logout_revokes_current_h5_session() -> None:
    settings = Settings(
        app_env="test",
        jwt_access_secret="a" * 32,
        jwt_refresh_secret="b" * 32,
        field_encryption_key="c" * 32,
        dev_fixed_otp="147258",
    )
    app = create_app(
        settings=settings,
        identity_repository=InMemoryIdentityRepository(),
    )

    with TestClient(app) as client:
        tokens = client.post(
            "/api/v1/h5/auth/login",
            json={"mobile": "18800000001", "code": "147258"},
        ).json()["data"]["tokens"]
        headers = {"Authorization": f"Bearer {tokens['access_token']}"}

        logout = client.post("/api/v1/h5/auth/logout", headers=headers)
        assert logout.status_code == 200

        profile = client.get("/api/v1/h5/me", headers=headers)
        assert profile.status_code == 401
        assert profile.json()["error"]["code"] == "AUTH_REQUIRED"


def test_h5_refresh_cookie_restores_session_without_request_body() -> None:
    settings = Settings(
        app_env="test",
        jwt_access_secret="a" * 32,
        jwt_refresh_secret="b" * 32,
        field_encryption_key="c" * 32,
        dev_fixed_otp="147258",
    )
    app = create_app(
        settings=settings,
        identity_repository=InMemoryIdentityRepository(),
    )

    with TestClient(app) as client:
        login = client.post(
            "/api/v1/h5/auth/login",
            json={"mobile": "18800000001", "code": "147258"},
        )
        assert "zbt_h5_refresh=" in login.headers["set-cookie"]
        assert "HttpOnly" in login.headers["set-cookie"]

        refreshed = client.post("/api/v1/h5/auth/refresh")
        assert refreshed.status_code == 200
        access_token = refreshed.json()["data"]["tokens"]["access_token"]

        logout = client.post(
            "/api/v1/h5/auth/logout",
            headers={"Authorization": f"Bearer {access_token}"},
        )
        assert logout.status_code == 200
        assert "zbt_h5_refresh=" in logout.headers["set-cookie"]
        assert "Max-Age=0" in logout.headers["set-cookie"]
