from unittest.mock import Mock

import pytest
from psycopg import Connection
from pytest_mock import MockFixture
from src.__types.index import Tenant
from src.domain.services.tenant_service import TenantService
from src.infrastructure.credential_manager import CredentialManager
from src.usecases.tenant_usecase import TenantUseCase


class TestTenantUseCase:
    @pytest.fixture
    def mock_tenant_service(self, mocker: MockFixture) -> Mock:
        return mocker.Mock(spec=TenantService)

    @pytest.fixture
    def mock_credential_manager(self, mocker: MockFixture) -> Mock:
        return mocker.Mock(spec=CredentialManager)

    @pytest.fixture
    def usecase(self, mock_tenant_service: Mock) -> TenantUseCase:
        return TenantUseCase(tenant_service=mock_tenant_service)

    class TestCreate:
        def test_create(self, mocker: MockFixture) -> None:
            """コンストラクタでTenantServiceを生成してTenantUseCaseを組み立てることを確認する。"""
            # Arrange
            mock_connection = mocker.Mock(spec=Connection)
            mock_credential_manager = mocker.Mock(spec=CredentialManager)
            expected_service = mocker.Mock(spec=TenantService)
            mock_create = mocker.patch(
                "src.usecases.tenant_usecase.TenantService.create",
                return_value=expected_service,
            )

            # Act
            actual = TenantUseCase.create(
                connection=mock_connection,
                credential_manager=mock_credential_manager,
            )

            # Assert
            mock_create.assert_called_once_with(
                connection=mock_connection,
                credential_manager=mock_credential_manager,
            )
            assert isinstance(actual, TenantUseCase)
            assert actual.tenant_service == expected_service

    class TestIssue:
        def test_delegates_to_tenant_service(
            self,
            usecase: TenantUseCase,
            mock_tenant_service: Mock,
            mock_tenant: Tenant,
        ) -> None:
            """issueがTenantServiceに委譲することを確認する。"""
            # Arrange
            mock_tenant_service.issue.return_value = mock_tenant

            # Act
            actual = usecase.issue(
                legal_name="ダミー株式会社",
                name="dummy-name",
                whi_customer_ids=["whi#dummy"],
                cydas_customer_ids=[],
            )

            # Assert
            mock_tenant_service.issue.assert_called_once_with(
                legal_name="ダミー株式会社",
                name="dummy-name",
                whi_customer_ids=["whi#dummy"],
                cydas_customer_ids=[],
            )
            assert actual == mock_tenant
