from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash

from app.extensions import db

try:
    import bcrypt
except ImportError:
    # روی بعضی محیط‌ها (مثل Termux/اندروید) کامپایل bcrypt ممکنه شکست بخوره —
    # در این حالت از هش pbkdf2 خودِ werkzeug (بدون نیاز به کامپایل) استفاده می‌کنیم.
    bcrypt = None


class User(db.Model, UserMixin):
    __tablename__ = "users"

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password_hash = db.Column(db.String(255), nullable=False)
    full_name = db.Column(db.String(120), nullable=False)
    role = db.Column(db.String(20), nullable=False, default="salesperson")  # 'admin' | 'salesperson'
    is_active_flag = db.Column("is_active", db.Boolean, nullable=False, default=True)
    created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())

    permissions = db.relationship(
        "Permission", backref="user", cascade="all, delete-orphan", lazy="selectin"
    )

    # UserMixin.is_active از پراپرتی زیر می‌خونه (نمی‌تونستیم ستون رو مستقیم is_active اسم بذاریم
    # چون UserMixin خودش is_active رو به‌عنوان پراپرتی همیشه-True تعریف کرده)
    @property
    def is_active(self):
        return self.is_active_flag

    def set_password(self, plain: str):
        if bcrypt:
            self.password_hash = bcrypt.hashpw(plain.encode("utf-8"), bcrypt.gensalt()).decode("utf-8")
        else:
            self.password_hash = generate_password_hash(plain)

    def check_password(self, plain: str) -> bool:
        stored = self.password_hash or ""
        if stored.startswith(("$2a$", "$2b$", "$2y$")):  # هش bcrypt
            if not bcrypt:
                return False
            try:
                return bcrypt.checkpw(plain.encode("utf-8"), stored.encode("utf-8"))
            except ValueError:
                return False
        try:
            return check_password_hash(stored, plain)
        except Exception:
            return False

    def permission_keys(self) -> set:
        return {p.page_key for p in self.permissions}

    def is_admin(self) -> bool:
        return self.role == "admin"


class Permission(db.Model):
    __tablename__ = "permissions"

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
    page_key = db.Column(db.String(50), nullable=False)

    __table_args__ = (db.UniqueConstraint("user_id", "page_key", name="uq_user_page"),)
