import uuid

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


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

    def test_creates_user(
        self,
        test_client: TestClient,
        registered_identifiers: dict[str, str],
        db_connection: psycopg.Connection,
    ) -> None:
        """認証テナントにユーザーを作成できることを確認する。"""
        display_id = f"it-post-{uuid.uuid4().hex[:8]}"
        email = f"{display_id}@example.com"
        payload = {
            "display_id": display_id,
            "display_name": "Integration Test User",
            "email": email,
        }

        try:
            response = test_client.post(url=self.PATH, json=payload)

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

            with db_connection.cursor() as cursor:
                cursor.execute(
                    """
                    SELECT display_id, display_name, email
                    FROM users
                    WHERE tenant_id = %s
                        AND display_id = %s;
                    """,
                    (registered_identifiers["tenant_alpha_id"], display_id),
                )
                assert cursor.fetchone() == (display_id, "Integration Test User", email)
        finally:
            with db_connection.cursor() as cursor:
                cursor.execute(
                    """
                    DELETE FROM users
                    WHERE tenant_id = %s
                        AND display_id = %s;
                    """,
                    (registered_identifiers["tenant_alpha_id"], display_id),
                )
                db_connection.commit()

    def test_display_id_already_exists(
        self,
        test_client: TestClient,
    ) -> None:
        """既存display_idでの作成を拒否できることを確認する。"""
        payload = {
            "display_id": "0001",
            "display_name": "Duplicated Display ID",
            "email": f"it-dup-display-{uuid.uuid4().hex[:8]}@example.com",
        }

        response = test_client.post(url=self.PATH, 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,
    ) -> None:
        """既存emailでの作成を拒否できることを確認する。"""
        payload = {
            "display_id": f"it-dup-email-{uuid.uuid4().hex[:8]}",
            "display_name": "Duplicated Email",
            "email": "test001@test.com",
        }

        response = test_client.post(url=self.PATH, 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,
    ) -> None:
        """display_id欠損のリクエストを拒否できることを確認する。"""
        payload = {
            "display_name": "Missing Display ID",
            "email": "missing.display.id@example.com",
        }

        response = test_client.post(url=self.PATH, 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,
    ) -> None:
        """email形式が不正なリクエストを拒否できることを確認する。"""
        payload = {
            "display_id": f"it-invalid-email-{uuid.uuid4().hex[:8]}",
            "display_name": "Invalid Email",
            "email": "invalid-email",
        }

        response = test_client.post(url=self.PATH, 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",
                },
            ],
        }
