"""UpdaterSpec implementations for user repository."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, override

from ai.backend.manager.models.hasher.types import PasswordInfo
from ai.backend.manager.models.user import UserRole, UserRow, UserStatus
from ai.backend.manager.repositories.base.updater import UpdaterSpec
from ai.backend.manager.types import OptionalState, TriState


@dataclass
class UserUpdaterSpec(UpdaterSpec[UserRow]):
    """UpdaterSpec for user updates.

    Note: User updates use email as the lookup key and have complex validation logic
    in the repository, so this spec is used with custom db_source logic.
    """

    username: OptionalState[str] = field(default_factory=OptionalState.nop)
    password: OptionalState[PasswordInfo] = field(default_factory=OptionalState.nop)
    need_password_change: OptionalState[bool] = field(default_factory=OptionalState.nop)
    full_name: OptionalState[str] = field(default_factory=OptionalState.nop)
    description: OptionalState[str] = field(default_factory=OptionalState.nop)
    is_active: OptionalState[bool] = field(default_factory=OptionalState.nop)
    status: OptionalState[UserStatus] = field(default_factory=OptionalState.nop)
    domain_name: OptionalState[str] = field(default_factory=OptionalState.nop)
    role: OptionalState[UserRole] = field(default_factory=OptionalState.nop)
    allowed_client_ip: TriState[list[str]] = field(default_factory=TriState.nop)
    totp_activated: OptionalState[bool] = field(default_factory=OptionalState.nop)
    resource_policy: OptionalState[str] = field(default_factory=OptionalState.nop)
    sudo_session_enabled: OptionalState[bool] = field(default_factory=OptionalState.nop)
    main_access_key: TriState[str] = field(default_factory=TriState.nop)
    container_uid: TriState[int] = field(default_factory=TriState.nop)
    container_main_gid: TriState[int] = field(default_factory=TriState.nop)
    container_gids: TriState[list[int]] = field(default_factory=TriState.nop)
    group_ids: OptionalState[list[str]] = field(default_factory=OptionalState.nop)

    @property
    @override
    def row_class(self) -> type[UserRow]:
        return UserRow

    @override
    def build_values(self) -> dict[str, Any]:
        to_update: dict[str, Any] = {}
        self.username.update_dict(to_update, "username")
        # Can't remove password - special handling
        password = self.password.optional_value()
        if password is not None:
            to_update["password"] = password
        self.need_password_change.update_dict(to_update, "need_password_change")
        self.full_name.update_dict(to_update, "full_name")
        self.description.update_dict(to_update, "description")
        self.is_active.update_dict(to_update, "is_active")
        self.domain_name.update_dict(to_update, "domain_name")
        self.role.update_dict(to_update, "role")
        self.allowed_client_ip.update_dict(to_update, "allowed_client_ip")
        self.totp_activated.update_dict(to_update, "totp_activated")
        self.resource_policy.update_dict(to_update, "resource_policy")
        self.sudo_session_enabled.update_dict(to_update, "sudo_session_enabled")
        self.main_access_key.update_dict(to_update, "main_access_key")
        self.container_uid.update_dict(to_update, "container_uid")
        self.container_main_gid.update_dict(to_update, "container_main_gid")
        self.container_gids.update_dict(to_update, "container_gids")
        # Set status based on is_active if not explicitly set
        status = self.status.optional_value()
        if status is not None:
            to_update["status"] = status
        else:
            is_active = self.is_active.optional_value()
            if is_active is not None:
                to_update["status"] = UserStatus.ACTIVE if is_active else UserStatus.INACTIVE
        return to_update

    @property
    def group_ids_value(self) -> list[str] | None:
        """Helper property for group_ids access."""
        return self.group_ids.optional_value()
