from uuid import UUID

import httpx
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.membership import TenantMembership
from app.models.types import MembershipRole
from app.models.user import UserProfile
from app.repositories.user import MembershipRepository, UserRepository
from app.schemas.user import MembershipCreate, UserCreate
from app.services.keycloak_client import KeycloakAdminClient
from shared.exceptions import ConflictError, NotFoundError


class UserService:
    def __init__(self, session: AsyncSession) -> None:
        self.session = session
        self.users = UserRepository(session)
        self.memberships = MembershipRepository(session)
        self.keycloak = KeycloakAdminClient()

    async def register(self, data: UserCreate) -> UserProfile:
        if data.mobile and await self.users.get_by_mobile(data.mobile):
            raise ConflictError("این شماره موبایل قبلاً ثبت شده است", error_code="mobile_taken")
        sub = await self.keycloak.create_user(
            email=data.email,
            username=data.username,
            password=data.password,
            display_name=data.display_name,
            mobile=data.mobile,
        )
        existing = await self.users.get_by_sub(sub)
        if existing:
            return existing
        user = UserProfile(
            keycloak_sub=sub,
            email=data.email,
            username=data.username,
            display_name=data.display_name,
            mobile=data.mobile,
            mobile_verified=False,
        )
        await self.users.add(user)
        await self.session.commit()
        await self.session.refresh(user)
        return user

    async def get(self, user_id: UUID) -> UserProfile:
        user = await self.users.get(user_id)
        if user is None:
            raise NotFoundError(f"کاربر یافت نشد: {user_id}")
        return user

    async def list_users(self, *, offset: int = 0, limit: int = 50) -> list[UserProfile]:
        return await self.users.list(offset=offset, limit=min(limit, 100))

    async def get_or_create_from_sub(
        self, *, sub: str, email: str | None, username: str | None
    ) -> UserProfile:
        user = await self.users.get_by_sub(sub)
        if user:
            return user
        user = UserProfile(
            keycloak_sub=sub,
            email=email or f"{sub}@unknown.local",
            username=username,
        )
        await self.users.add(user)
        await self.session.commit()
        await self.session.refresh(user)
        return user

    async def add_member(
        self, tenant_id: UUID, data: MembershipCreate, *, authorization: str | None = None
    ) -> TenantMembership:
        await self._assert_tenant_exists(tenant_id, authorization=authorization)
        user = await self.get(data.user_id)
        if await self.memberships.get(tenant_id, user.id):
            raise ConflictError("کاربر قبلاً عضو این tenant است")
        membership = TenantMembership(
            tenant_id=tenant_id, user_id=user.id, role=data.role
        )
        await self.memberships.add(membership)
        await self.session.commit()
        await self.session.refresh(membership)
        return membership

    async def list_members(self, tenant_id: UUID) -> list[TenantMembership]:
        return await self.memberships.list_by_tenant(tenant_id)

    async def _assert_tenant_exists(
        self, tenant_id: UUID, *, authorization: str | None = None
    ) -> None:
        from app.core.config import settings

        headers = {}
        if authorization:
            headers["Authorization"] = authorization
        async with httpx.AsyncClient(timeout=5.0) as client:
            resp = await client.get(
                f"{settings.core_service_url}/api/v1/tenants/{tenant_id}",
                headers=headers,
            )
            if resp.status_code == 404:
                raise NotFoundError(f"tenant یافت نشد: {tenant_id}")
            resp.raise_for_status()
