import uuid

import pytest
from fastapi import status
from fastapi.testclient import TestClient


@pytest.mark.usefixtures("mock_cognito_client")
class TestUserPut:
    PATH = "/v1/users"

    def test_updates_user(
        self,
        test_client: TestClient,
        registered_identifiers: dict[str, str],
    ) -> None:
        """認証テナントに紐づくユーザーを更新できることを確認する。"""
        user_id = registered_identifiers["user_alpha_member_id"]
        payload = {
            "display_id": "0001-updated",
            "display_name": "社員001#アルファ株式会社(更新)",
            "email": "test001.updated@test.com",
        }

        try:
            response = test_client.put(url=f"{self.PATH}/{user_id}", json=payload)

            assert response.status_code == status.HTTP_204_NO_CONTENT
            assert response.content == b""

            get_response = test_client.get(url=f"{self.PATH}/{user_id}")
            assert get_response.status_code == status.HTTP_200_OK
            assert get_response.json() == {
                "id": user_id,
                "display_id": payload["display_id"],
                "display_name": payload["display_name"],
                "email": payload["email"],
            }
        finally:
            restore_payload = {
                "display_id": "0001",
                "display_name": "社員001#アルファ株式会社",
                "email": "test001@test.com",
            }
            restore_response = test_client.put(
                url=f"{self.PATH}/{user_id}",
                json=restore_payload,
            )
            assert restore_response.status_code == status.HTTP_204_NO_CONTENT

    def test_user_not_found(
        self,
        test_client: TestClient,
        registered_identifiers: dict[str, str],
    ) -> None:
        """認証テナントに紐づかないユーザー更新リクエストを拒否できることを確認する。"""
        payload = {
            "display_id": "beta-0001",
            "display_name": "Beta User",
            "email": "beta.user@example.com",
        }

        response = test_client.put(url=f"{self.PATH}/{registered_identifiers['user_beta_member_id']}", json=payload)

        assert response.status_code == status.HTTP_404_NOT_FOUND
        assert response.json() == {
            "detail": "Requested resource was not found.",
            "invalid_parameters": None,
        }

    def test_display_id_already_exists(
        self,
        test_client: TestClient,
        registered_identifiers: dict[str, str],
    ) -> None:
        """別ユーザーのdisplay_idと重複する更新リクエストを拒否できることを確認する。"""
        target_user_id = registered_identifiers["user_alpha_member2_id"]
        payload = {
            "display_id": "0001",
            "display_name": "Duplicated Display ID",
            "email": f"it-put-dup-display-{uuid.uuid4().hex[:8]}@example.com",
        }

        response = test_client.put(url=f"{self.PATH}/{target_user_id}", json=payload)

        assert response.status_code == status.HTTP_409_CONFLICT
        assert response.json() == {
            "detail": "Conflict detected for one or more fields.",
            "invalid_parameters": [
                {
                    "name": "display_id",
                    "code": "ALREADY_EXISTS",
                },
            ],
        }

    def test_email_already_exists(
        self,
        test_client: TestClient,
        registered_identifiers: dict[str, str],
    ) -> None:
        """別ユーザーのemailと重複する更新リクエストを拒否できることを確認する。"""
        target_user_id = registered_identifiers["user_alpha_member2_id"]
        payload = {
            "display_id": f"it-put-dup-email-{uuid.uuid4().hex[:8]}",
            "display_name": "Duplicated Email",
            "email": "test001@test.com",
        }

        response = test_client.put(url=f"{self.PATH}/{target_user_id}", json=payload)

        assert response.status_code == status.HTTP_409_CONFLICT
        assert response.json() == {
            "detail": "Conflict detected for one or more fields.",
            "invalid_parameters": [
                {
                    "name": "email",
                    "code": "ALREADY_EXISTS",
                },
            ],
        }

    def test_display_id_missing(
        self,
        test_client: TestClient,
        registered_identifiers: dict[str, str],
    ) -> None:
        """display_id欠損の更新リクエストを拒否できることを確認する。"""
        target_user_id = registered_identifiers["user_alpha_member_id"]
        payload = {
            "display_name": "Missing Display ID",
            "email": "missing.display.id@example.com",
        }

        response = test_client.put(url=f"{self.PATH}/{target_user_id}", json=payload)

        assert response.status_code == status.HTTP_422_UNPROCESSABLE_CONTENT
        assert response.json() == {
            "detail": "Validation failed for one or more fields.",
            "invalid_parameters": [
                {
                    "name": "display_id",
                    "code": "REQUIRED",
                },
            ],
        }

    def test_email_invalid_format(
        self,
        test_client: TestClient,
        registered_identifiers: dict[str, str],
    ) -> None:
        """email形式が不正な更新リクエストを拒否できることを確認する。"""
        target_user_id = registered_identifiers["user_alpha_member_id"]
        payload = {
            "display_id": "put-invalid-email",
            "display_name": "Invalid Email",
            "email": "invalid-email",
        }

        response = test_client.put(url=f"{self.PATH}/{target_user_id}", json=payload)

        assert response.status_code == status.HTTP_422_UNPROCESSABLE_CONTENT
        assert response.json() == {
            "detail": "Validation failed for one or more fields.",
            "invalid_parameters": [
                {
                    "name": "email",
                    "code": "INVALID_FORMAT",
                },
            ],
        }

    def test_updates_with_same_values(
        self,
        test_client: TestClient,
        registered_identifiers: dict[str, str],
    ) -> None:
        """同一値での更新リクエストを受け付けることを確認する。"""
        user_id = registered_identifiers["user_alpha_member_id"]
        payload = {
            "display_id": "0001",
            "display_name": "社員001#アルファ株式会社",
            "email": "test001@test.com",
        }

        response = test_client.put(url=f"{self.PATH}/{user_id}", json=payload)

        assert response.status_code == status.HTTP_204_NO_CONTENT
        assert response.content == b""
