# backend/app/connectors/registry.py — CONNECTOR_<DOMAIN> 로 mock|real 선택하는 단일 지점.
# 페이지/라우터는 항상 레지스트리를 통해서만 sync 커넥터를 얻는다(코드 불변의 핵심).
from sqlmodel import Session, select

from ..config import get_settings
from ..models import ConnectorAccount
from .base import BaseConnector


def _impl(domain: str, mode: str, provider: str = ""):
    """도메인 × 모드 → 구현 클래스 (lazy import 로 의존성 격리)."""
    if domain == "mail":  # mock 제거(phase-16+): 실 계정만 동기화
        if mode == "real":  # real 메일은 provider 로 Gmail/Outlook 분기
            from .mail.real_gmail import GmailConnector
            from .mail.real_outlook import OutlookConnector

            return OutlookConnector if provider == "outlook" else GmailConnector
        if mode == "imap":
            from .mail.real_imap import ImapConnector

            return ImapConnector
        raise ValueError(f"unsupported mail connector mode: {mode}")
    if domain == "calendar":  # mock 제거(phase-16+)
        if mode == "real":  # real 캘린더는 provider 로 Google/Outlook 분기
            if provider == "outlook_calendar":
                from .calendar.real_outlook import OutlookCalendarConnector

                return OutlookCalendarConnector
            from .calendar.real_google import GoogleCalendarConnector

            return GoogleCalendarConnector
        if mode == "ics":
            from .calendar.ics_import import IcsConnector

            return IcsConnector
        raise ValueError(f"unsupported calendar connector mode: {mode}")
    raise ValueError(f"unknown domain {domain}")


class ConnectorRegistry:
    @staticmethod
    def mode_for(domain) -> str:
        dom = domain.value if hasattr(domain, "value") else str(domain)
        return getattr(get_settings(), f"connector_{dom}", "mock")

    @staticmethod
    def effective_mode(account: ConnectorAccount) -> str:
        """모드 결정 정본:
        - 계정 mode 가 mock 이 아니면(real/csv/healthkit/ics) 그 모드를 쓴다(연결된 계정).
        - 시드 mock 계정은 env=real 이어도 mock 유지(데모 결정성).
        - csv/healthkit/ics env 면 그 모드를 따른다(로컬 우선 임포트)."""
        env_mode = ConnectorRegistry.mode_for(account.domain)
        acct_mode = account.mode.value if hasattr(account.mode, "value") else str(account.mode)
        if acct_mode != "mock":
            return acct_mode
        return "mock" if env_mode == "real" else env_mode

    @staticmethod
    def get(session: Session, account: ConnectorAccount) -> BaseConnector:
        mode = ConnectorRegistry.effective_mode(account)
        dom = account.domain.value if hasattr(account.domain, "value") else account.domain
        return _impl(dom, mode, account.provider)(account)

    @staticmethod
    def accounts(session: Session, domain: str | None = None) -> list[ConnectorAccount]:
        q = select(ConnectorAccount)
        if domain:
            q = q.where(ConnectorAccount.domain == domain)
        return session.exec(q.order_by(ConnectorAccount.id)).all()
