from uuid import UUID

from src.__types.errors import IdentityProviderError, ResourceDuplicatedError
from src.__types.index import UserWriteAttribute
from src.infrastructure.repositories.user_identity_repository import UserIdentityRepository
from src.infrastructure.repositories.user_repository import UserRepository
from src.logger import logger


class UserService:
    """ユーザーに関するサービス"""

    def __init__(
        self,
        user_repository: UserRepository,
        user_identity_repository: UserIdentityRepository,
    ) -> None:
        self.user_repository = user_repository
        self.user_identity_repository = user_identity_repository

    def bulk_add(self, users: list[UserWriteAttribute]) -> None:
        """ユーザーを一括追加する。

        UserPoolのユーザー作成はDBのIDに依存するため、DB → UserPoolの順でユーザーを作成する。
        UserPoolのユーザー作成失敗時には、作成済みのDB・UserPoolユーザーを全て削除してロールバックする。
        """
        created_users = self.user_repository.bulk_create(users=users)
        succeeded_user_ids: list[UUID] = []

        try:
            for user in created_users:
                self.user_identity_repository.create_user(user=user)
                succeeded_user_ids.append(user.id)
        except (IdentityProviderError, ResourceDuplicatedError):
            logger.warning("UserPool failed: Could not create users. Cleanup db and UserPool users.")
            self._cleanup_bulk_created_users(
                db_user_ids=[u.id for u in created_users],
                userpool_user_ids=succeeded_user_ids,
                user_identity_repository=self.user_identity_repository,
                user_repository=self.user_repository,
            )
            raise

    def _cleanup_bulk_created_users(
        self,
        db_user_ids: list[UUID],
        userpool_user_ids: list[UUID],
        user_identity_repository: UserIdentityRepository,
        user_repository: UserRepository,
    ) -> None:
        """一括追加の失敗時に作成済みのDB・UserPoolユーザーを削除する。

        クリーンアップ中の例外で元の例外が隠れないよう、個別の例外はログに残して握りつぶす。
        """
        try:
            user_repository.bulk_delete(user_ids=db_user_ids)
        except Exception:  # noqa: BLE001
            logger.exception("Cleanup failed: Could not delete users from DB.", user_ids=db_user_ids)

        for uid in userpool_user_ids:
            try:
                user_identity_repository.delete_user(user_id=uid)
            except Exception:  # noqa: PERF203, BLE001
                logger.exception("Cleanup failed: Could not delete user from UserPool.", user_id=uid)
