"""Explicit operator cutover from committed customer activation to ACTIVE bootstrap."""

from __future__ import annotations

import importlib
import sys
from collections.abc import Sequence
from dataclasses import dataclass
from datetime import date
from pathlib import Path
from typing import Callable, Protocol, cast

from .telegram_customer_bootstrap import (
    BootstrapConflict,
    BootstrapError,
    BootstrapState,
    GenerationConflict,
    Role,
    RoomBootstrapSession,
    RoomBootstrapStore,
    room_bootstrap_state_dir,
)


class ActivationCutoverError(BootstrapError):
    pass


class _CustomerAdmin(Protocol):
    __file__: str | None

    def activate_customer(
        self,
        profile_root: Path,
        data_root: Path,
        customer_id: str,
        checklist_evidence_path: Path,
        *,
        kst_date: date | None,
    ) -> object: ...

    def validate_committed_activation(
        self,
        profile_root: Path,
        registry_path: Path | None = None,
        customer_id: str | None = None,
    ) -> bool: ...


@dataclass(frozen=True, slots=True)
class ActivationCutoverResult:
    customer_id: str
    session_id: str
    generation: int
    state: BootstrapState
    reconciled: bool

    def to_dict(self) -> dict[str, object]:
        return {
            "customer_id": self.customer_id,
            "session_id": self.session_id,
            "generation": self.generation,
            "state": self.state.value,
            "reconciled": self.reconciled,
        }


def activate_customer_cutover(
    profile_root: Path | str,
    data_root: Path | str,
    customer_id: str,
    checklist_evidence_path: Path | str,
    *,
    bootstrap_session_id: str,
    expected_generation: int,
    package_root: Path | str | None = None,
    kst_date: date | None = None,
) -> ActivationCutoverResult:
    """Commit customer activation, then its exact bootstrap lifecycle."""
    root = _profile_root(profile_root)
    state_dir = room_bootstrap_state_dir(root)
    if not state_dir.is_dir() or not (state_dir / "ledger.json").is_file():
        raise ActivationCutoverError("customer bootstrap authority is unavailable")
    store = RoomBootstrapStore(state_dir)
    session = _preflight_bootstrap(
        store,
        bootstrap_session_id,
        expected_generation=expected_generation,
        customer_id=customer_id,
    )
    admin = _profile_admin(root, package_root)
    registry_path = _admin_registry_path(admin, root)
    document = _admin_read(admin, registry_path)
    customer = _preflight_registry(document, session, customer_id)
    enabled = getattr(customer, "enabled", None)
    if enabled is True:
        _validate_committed(admin, root, registry_path, customer_id)
        reconciled = session.state is not BootstrapState.ACTIVE
    elif enabled is False:
        if session.state is BootstrapState.ACTIVE:
            raise ActivationCutoverError(
                "active bootstrap has no committed customer activation"
            )
        _ = admin.activate_customer(
            root,
            Path(data_root),
            customer_id,
            Path(checklist_evidence_path),
            kst_date=kst_date,
        )
        _validate_committed(admin, root, registry_path, customer_id)
        reconciled = False
    else:
        raise ActivationCutoverError("customer activation state is invalid")
    committed = _activate_bootstrap(
        store,
        session,
        customer_id=customer_id,
    )
    return ActivationCutoverResult(
        customer_id,
        committed.session_id,
        committed.generation,
        committed.state,
        reconciled,
    )


def _preflight_bootstrap(
    store: RoomBootstrapStore,
    session_id: str,
    *,
    expected_generation: int,
    customer_id: str,
) -> RoomBootstrapSession:
    session = store.get(session_id)
    allowed_generation = (
        {session.generation, session.generation - 1}
        if session.state is BootstrapState.ACTIVE
        else {session.generation}
    )
    customer = session.role_claim(Role.CUSTOMER)
    if (
        expected_generation not in allowed_generation
        or session.customer_key != customer_id
        or session.state
        not in {BootstrapState.AWAITING_ACTIVATION, BootstrapState.ACTIVE}
        or customer is None
        or len(session.role_claims) != 1
        or customer.user_id != customer.chat_id
        or customer.topic_id != "0"
        or customer.user_id != session.customer_draft.customer_user_id
        or customer.user_id == session.owner_id
    ):
        raise GenerationConflict("customer activation cutover authority is stale")
    competing = tuple(
        item
        for item in store.list_sessions()
        if item.session_id != session.session_id
        and item.customer_key == customer_id
        and item.state
        in {BootstrapState.AWAITING_ACTIVATION, BootstrapState.ACTIVE}
    )
    if competing:
        raise BootstrapConflict("customer has multiple activation lifecycles")
    return session


def _preflight_registry(
    document: object,
    session: RoomBootstrapSession,
    customer_id: str,
) -> object:
    owner = getattr(document, "owner", None)
    raw_customers = getattr(document, "customers", None)
    if not isinstance(raw_customers, (tuple, list)):
        raise ActivationCutoverError("customer registry identity is unavailable")
    customers = cast(Sequence[object], raw_customers)
    matches = tuple(
        item
        for item in customers
        if getattr(item, "customer_key", None) == customer_id
    )
    claim = session.role_claim(Role.CUSTOMER)
    if len(matches) != 1 or claim is None:
        raise ActivationCutoverError("customer registry identity is unavailable")
    telegram = getattr(matches[0], "telegram", None)
    if (
        str(getattr(owner, "user_id", "")) != session.owner_id
        or str(getattr(telegram, "user_id", "")) != claim.user_id
        or str(getattr(telegram, "chat_id", "")) != claim.chat_id
        or str(getattr(telegram, "topic_id", "")) != claim.topic_id
    ):
        raise ActivationCutoverError("customer registry identity is stale")
    return matches[0]


def _activate_bootstrap(
    store: RoomBootstrapStore,
    session: RoomBootstrapSession,
    *,
    customer_id: str,
) -> RoomBootstrapSession:
    customer = session.role_claim(Role.CUSTOMER)
    if customer is None:
        raise ActivationCutoverError("customer bootstrap identity is unavailable")
    return store.activate_bound_customer(
        session.session_id,
        expected_generation=session.generation,
        customer_key=customer_id,
        customer_user_id=customer.user_id,
        owner_id=session.owner_id,
    )


def _admin_registry_path(admin: _CustomerAdmin, root: Path) -> Path:
    resolve = cast(
        Callable[[Path], Path],
        getattr(admin, "_resolve_registry_path"),
    )
    return resolve(root)


def _admin_read(admin: _CustomerAdmin, path: Path) -> object:
    read = cast(Callable[[Path], object], getattr(admin, "_read"))
    return read(path)


def _validate_committed(
    admin: _CustomerAdmin,
    root: Path,
    registry_path: Path,
    customer_id: str,
) -> None:
    if admin.validate_committed_activation(root, registry_path, customer_id) is not True:
        raise ActivationCutoverError("committed customer activation is unavailable")


def _profile_root(value: Path | str) -> Path:
    root = Path(value)
    if root.is_symlink() or not root.is_dir():
        raise ActivationCutoverError("activation profile root is unavailable")
    return root.resolve()


def _profile_admin(
    root: Path, package_root: Path | str | None
) -> _CustomerAdmin:
    configured = Path(package_root or root / "workspace" / "checkin_cli").resolve()
    package = configured / "checkin_cli"
    source_path = package / "customer_admin.py"
    if not package.is_dir() or not source_path.is_file() or source_path.is_symlink():
        raise ActivationCutoverError("profile-local checkin_cli is unavailable")
    root_text = str(configured)
    if root_text not in sys.path:
        sys.path.insert(0, root_text)
    admin = importlib.import_module("checkin_cli.customer_admin")
    source = Path(str(admin.__file__)).resolve()
    if source != source_path.resolve():
        raise ActivationCutoverError("loaded checkin_cli is not profile-local")
    return cast(_CustomerAdmin, cast(object, admin))


__all__ = [
    "ActivationCutoverError",
    "ActivationCutoverResult",
    "activate_customer_cutover",
]
