from template_project.application.common.data_structure import to_data_structure
from template_project.application.common.identity_provider import IdentityProvider
from template_project.application.common.interactor import to_interactor
from template_project.application.common.unit_of_work import UnitOfWork
from template_project.application.user.entity import UserId
from template_project.application.user.profile.data_gateway import ProfileDataGateway
from template_project.application.user.profile.entity import Profile


@to_data_structure
class PatchProfileRequest:
    email: str | None = None
    display_name: str | None = None
    first_name: str | None = None
    last_name: str | None = None
    avatar_url: str | None = None
    phone: str | None = None


@to_data_structure
class PatchProfileResponse:
    id: UserId
    email: str | None
    display_name: str | None
    first_name: str | None
    last_name: str | None
    avatar_url: str | None
    phone: str | None


@to_interactor
class PatchProfileInteractor:
    identity_provider: IdentityProvider
    profile_data_gateway: ProfileDataGateway
    unit_of_work: UnitOfWork

    async def execute(self, request: PatchProfileRequest) -> PatchProfileResponse:
        current_user = await self.identity_provider.get_current_user()
        profile = await self.profile_data_gateway.load_by_user_id(current_user.id)

        if profile:
            for attr in ("email", "display_name", "first_name", "last_name", "avatar_url", "phone"):
                value = getattr(request, attr)
                if value is not None:
                    setattr(profile, attr, value)

            await self.unit_of_work.add(profile)
        else:
            profile = Profile.factory(
                user_id=current_user.id,
                email=request.email,
                display_name=request.display_name,
                first_name=request.first_name,
                last_name=request.last_name,
                avatar_url=request.avatar_url,
                phone=request.phone,
            )
            await self.unit_of_work.add(profile)

        await self.unit_of_work.commit()

        return PatchProfileResponse(
            id=profile.user_id,
            email=profile.email,
            display_name=profile.display_name,
            first_name=profile.first_name,
            last_name=profile.last_name,
            avatar_url=profile.avatar_url,
            phone=profile.phone,
        )
