from __future__ import annotations

from typing import TYPE_CHECKING

from fastapi import HTTPException
from sqlalchemy.exc import SQLAlchemyError

from core.auth.models import CurrentUser
from core.db.base_service import BaseService
from core.logging import get_logger
from v1.profile.repository import ProfileRepository
from v1.profile.schemas import ProfileResponse, ProfileUpdateRequest

if TYPE_CHECKING:
    from sqlalchemy.ext.asyncio import AsyncSession

logger = get_logger("v1.profile.service")


class ProfileService(BaseService):
    """Profile service handling business logic and transactions.

    Responsibilities:
    - Authorization checks
    - Transaction boundary (commit/rollback)
    - Converting ORM models to response schemas
    """

    _repository: ProfileRepository
    _session: AsyncSession

    def __init__(
        self,
        repository: ProfileRepository,
        session: AsyncSession,
        current_user: CurrentUser | None,
    ) -> None:
        super().__init__(current_user=current_user)
        self._repository = repository
        self._session = session

    async def get_me(self) -> ProfileResponse:
        user_id = self.require_user_id()
        try:
            profile = await self._repository.get_by_user_id(user_id)
        except SQLAlchemyError:
            raise HTTPException(status_code=503, detail="Profile store unavailable")

        if profile is None:
            raise HTTPException(status_code=404, detail="Profile not found")
        return ProfileResponse(
            id=str(profile.id),
            username=profile.username,
            avatar_url=profile.avatar_url,
            bio=profile.bio,
        )

    async def update_me(self, update: ProfileUpdateRequest) -> ProfileResponse:
        user_id = self.require_user_id()
        update_data: dict[str, str | None] = {
            key: value
            for key, value in {
                "username": update.username,
                "avatar_url": update.avatar_url,
                "bio": update.bio,
            }.items()
            if value is not None
        }

        if not update_data:
            raise HTTPException(status_code=400, detail="No fields to update")

        try:
            profile = await self._repository.update_by_user_id(user_id, update_data)
            await self._session.commit()
        except SQLAlchemyError:
            await self._session.rollback()
            raise HTTPException(status_code=503, detail="Profile store unavailable")

        if profile is None:
            raise HTTPException(status_code=404, detail="Profile not found")

        return ProfileResponse(
            id=str(profile.id),
            username=profile.username,
            avatar_url=profile.avatar_url,
            bio=profile.bio,
        )

    async def get_by_username(self, username: str) -> ProfileResponse:
        try:
            profile = await self._repository.get_by_username(username)
        except SQLAlchemyError:
            raise HTTPException(status_code=503, detail="Profile store unavailable")

        if profile is None:
            raise HTTPException(status_code=404, detail="Profile not found")
        return ProfileResponse(
            id=str(profile.id),
            username=profile.username,
            avatar_url=profile.avatar_url,
            bio=profile.bio,
        )
