# app/modules/tenancy/models/user.py
"""
User model with authentication support.

ROLE SYSTEM (Phase 1 — Consolidated 4-value enum):
- User.role contains one of 4 values:
  * "super_admin"    — Platform super administrator (all platforms, all settings)
  * "platform_admin" — Platform admin scoped to assigned platforms
  * "merchant_owner" — Owns merchant(s) and all their stores
  * "store_member"   — Team member on specific store(s)

- Store-specific granular permissions are in StoreUser.role_id -> Role.permissions
- Customers are NOT in the User table — they use the Customer model
"""

import enum

from sqlalchemy import Boolean, Column, DateTime, Index, Integer, String
from sqlalchemy.orm import relationship

from app.core.database import Base
from models.database.base import SoftDeleteMixin, TimestampMixin


class UserRole(str, enum.Enum):
    """Platform-level user roles."""

    SUPER_ADMIN = "super_admin"        # Platform super administrator
    PLATFORM_ADMIN = "platform_admin"  # Platform admin (scoped to assigned platforms)
    MERCHANT_OWNER = "merchant_owner"  # Owns merchant(s) and all their stores
    STORE_MEMBER = "store_member"      # Team member on specific store(s)


class User(Base, TimestampMixin, SoftDeleteMixin):
    """Represents a platform user (admins, merchant owners, and store team)."""

    __tablename__ = "users"
    __table_args__ = (
        Index("uq_users_email_active", "email", unique=True, postgresql_where="deleted_at IS NULL"),
        Index("uq_users_username_active", "username", unique=True, postgresql_where="deleted_at IS NULL"),
    )

    id = Column(Integer, primary_key=True, index=True)
    email = Column(String, index=True, nullable=False)
    username = Column(String, index=True, nullable=False)
    first_name = Column(String)
    last_name = Column(String)
    hashed_password = Column(String, nullable=False)

    # Consolidated role — one of: super_admin, platform_admin, merchant_owner, store_member
    role = Column(String, nullable=False, default=UserRole.STORE_MEMBER.value)

    is_active = Column(Boolean, default=True, nullable=False)
    is_email_verified = Column(Boolean, default=False, nullable=False)
    last_login = Column(DateTime, nullable=True)

    # Language preference (NULL = use context default: store dashboard_language or system default)
    # Supported: en, fr, de, lb
    preferred_language = Column(String(5), nullable=True)

    # Relationships
    # NOTE: marketplace_import_jobs relationship removed - owned by marketplace module
    # Use: MarketplaceImportJob.query.filter_by(user_id=user.id) instead
    owned_merchants = relationship("Merchant", foreign_keys="[Merchant.owner_user_id]", back_populates="owner")
    store_memberships = relationship(
        "StoreUser", foreign_keys="[StoreUser.user_id]", back_populates="user"
    )

    # Admin-platform assignments (for platform admins only)
    # Super admins don't need assignments - they have access to all platforms
    admin_platforms = relationship(
        "AdminPlatform",
        foreign_keys="AdminPlatform.user_id",
        back_populates="user",
        cascade="all, delete-orphan",
    )

    # Menu visibility configuration (for super admins only)
    # Platform admins get menu config from their platform, not user-level
    menu_configs = relationship(
        "AdminMenuConfig",
        foreign_keys="AdminMenuConfig.user_id",
        back_populates="user",
        cascade="all, delete-orphan",
    )

    def __repr__(self):
        """String representation of the User object."""
        return f"<User(id={self.id}, username='{self.username}', email='{self.email}', role='{self.role}')>"

    @property
    def full_name(self):
        """Returns the full name of the user, combining first and last names if available."""
        if self.first_name and self.last_name:
            return f"{self.first_name} {self.last_name}"
        return self.username

    # =========================================================================
    # Role-checking properties
    # =========================================================================

    @property
    def is_super_admin(self) -> bool:
        """Check if user is a super admin."""
        return self.role == UserRole.SUPER_ADMIN.value

    @property
    def is_admin(self) -> bool:
        """Check if user is any kind of platform admin (super or scoped)."""
        return self.role in (UserRole.SUPER_ADMIN.value, UserRole.PLATFORM_ADMIN.value)

    @property
    def is_platform_admin(self) -> bool:
        """Check if user is a scoped platform admin (not super admin)."""
        return self.role == UserRole.PLATFORM_ADMIN.value

    @property
    def is_merchant_owner(self) -> bool:
        """Check if user is a merchant owner."""
        return self.role == UserRole.MERCHANT_OWNER.value

    @property
    def is_store_user(self) -> bool:
        """Check if user is a merchant owner or store member."""
        return self.role in (UserRole.MERCHANT_OWNER.value, UserRole.STORE_MEMBER.value)

    def is_owner_of(self, store_id: int) -> bool:
        """
        Check if user is the owner of a specific store.

        Ownership is determined via merchant ownership:
        User owns Merchant -> Merchant has Store -> User owns Store
        """
        for merchant in self.owned_merchants:
            if any(v.id == store_id for v in merchant.stores):
                return True
        return False

    def is_member_of(self, store_id: int) -> bool:
        """Check if user is a member of a specific store (owner or team)."""
        # Check if owner (via merchant)
        if self.is_owner_of(store_id):
            return True
        # Check if team member
        return any(
            vm.store_id == store_id and vm.is_active for vm in self.store_memberships
        )

    def get_store_role(self, store_id: int) -> str:
        """Get user's role within a specific store."""
        # Check if owner (via merchant)
        if self.is_owner_of(store_id):
            return "owner"

        # Check team membership
        for vm in self.store_memberships:
            if vm.store_id == store_id and vm.is_active:
                return vm.role.name if vm.role else "member"

        return None

    def has_store_permission(self, store_id: int, permission: str) -> bool:
        """Check if user has a specific permission in a store."""
        # Owners have all permissions
        if self.is_owner_of(store_id):
            return True

        # Check team member permissions
        for vm in self.store_memberships:
            if vm.store_id == store_id and vm.is_active:
                if vm.role and permission in vm.role.permissions:
                    return True

        return False

    # =========================================================================
    # Admin Platform Access Methods
    # =========================================================================

    def can_access_platform(self, platform_id: int) -> bool:
        """
        Check if admin can access a specific platform.

        - Super admins can access all platforms
        - Platform admins can only access assigned platforms
        - Non-admins return False
        """
        if not self.is_admin:
            return False
        if self.is_super_admin:
            return True
        return any(
            ap.platform_id == platform_id and ap.is_active
            for ap in self.admin_platforms
        )

    def get_accessible_platform_ids(self) -> list[int] | None:
        """
        Get list of platform IDs this admin can access.

        Returns:
            - None for super admins (means ALL platforms)
            - List of platform IDs for platform admins
            - Empty list for non-admins
        """
        if not self.is_admin:
            return []
        if self.is_super_admin:
            return None  # None means ALL platforms
        return [ap.platform_id for ap in self.admin_platforms if ap.is_active]


__all__ = ["User", "UserRole"]
