from typing import Optional, Iterable
from django.db.models import Q

from apps.companies.models import Company
from apps.userprofile.models import UserProfile
from apps.companies.models import CompanyBotSettings
from utils.normalize_phone import normalize_phone


class PhoneUniquenessService:
    """
    Ensures a phone number is globally unique across:
    - Company.phone
    - UserProfile.phone_number
    - CompanyBotSettings.phone_number
    """

    @staticmethod
    def normalize(value: str) -> str:
        return normalize_phone(value)

    @staticmethod
    def possible_matches(value: str) -> set[str]:
        canonical = normalize_phone(value)
        return {
            canonical,
            canonical.lstrip("+"),
            value,
        }

    @classmethod
    def assert_unique(
        cls,
        value: str,
        *,
        exclude_company_id: Optional[int] = None,
        exclude_user_id: Optional[int] = None,
        exclude_bot_id: Optional[int] = None,
    ) -> str:
        if not value:
            return value

        canonical = cls.normalize(value)
        matches = cls.possible_matches(value)

        # ---- Company ----
        company_qs = Company.objects.filter(phone__in=matches)
        if exclude_company_id:
            company_qs = company_qs.exclude(id=exclude_company_id)

        if company_qs.exists():
            raise ValueError("Phone number already exists for a company.")

        # ---- User ----
        user_qs = UserProfile.objects.filter(phone_number__in=matches)
        if exclude_user_id:
            user_qs = user_qs.exclude(user_id=exclude_user_id)

        if user_qs.exists():
            raise ValueError("Phone number already exists for a staff.")

        # ---- Bot ----
        bot_qs = CompanyBotSettings.objects.filter(phone_number__in=matches)
        if exclude_bot_id:
            bot_qs = bot_qs.exclude(id=exclude_bot_id)

        if bot_qs.exists():
            raise ValueError("Phone number already exists for a bot.")

        return canonical
