# app/models/user.py

from flask_login import UserMixin
from datetime import datetime
from app.extensions import db, login_manager
from werkzeug.security import generate_password_hash, check_password_hash
import base64
import json
import numpy as np


class User(UserMixin, db.Model):
    """مدل کاربران سیستم با قابلیت چندنقشی"""
    __tablename__ = 'users'
    __table_args__ = {'extend_existing': True}
    
    # ========== فیلدهای اصلی ==========
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    password_hash = db.Column(db.String(200), nullable=False)
    fullname = db.Column(db.String(100), nullable=False)
    national_code = db.Column(db.String(10), unique=True, nullable=True)
    phone = db.Column(db.String(11), unique=True, nullable=False)
    email = db.Column(db.String(120), nullable=True)
    address = db.Column(db.String(300), nullable=True)
    postal_code = db.Column(db.String(10), nullable=True)
    is_new_user = db.Column(db.Boolean, default=False)
    
    # ========== فیلدهای نقش ==========
    # نقش اصلی (برای سازگاری با کدهای قدیمی)
    role = db.Column(db.String(20), nullable=False, default='employee')
    
    # لیست نقش‌ها به صورت JSON (ویژگی جدید)
    _roles = db.Column('roles', db.Text, default='["employee"]')
    
    # اطلاعات سیستمی
    is_active = db.Column(db.Boolean, default=True)
    is_verified = db.Column(db.Boolean, default=False)
    is_temp_password = db.Column(db.Boolean, default=False)
    
    # اطلاعات GPS
    gps_lat = db.Column(db.Float, nullable=True)
    gps_lon = db.Column(db.Float, nullable=True)
    gps_accuracy = db.Column(db.Float, nullable=True)
    gps_updated_at = db.Column(db.DateTime, nullable=True)
    
    # اطلاعات چهره
    face_encoding = db.Column(db.Text, nullable=True)
    face_image_path = db.Column(db.String(300), nullable=True)
    face_verified_at = db.Column(db.DateTime, nullable=True)
    face_verification_attempts = db.Column(db.Integer, default=0)
    face_threshold = db.Column(db.Float, default=0.6)
    
    # رمز موقت
    temp_password = db.Column(db.String(20), nullable=True)
    temp_password_expires = db.Column(db.DateTime, nullable=True)
    
    # برای مدیران پروژه
    manager_request_status = db.Column(db.String(20), default='pending')
    manager_request_note = db.Column(db.Text, nullable=True)
    manager_approved_at = db.Column(db.DateTime, nullable=True)
    manager_approved_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    
    # زمان‌ها
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    last_login = db.Column(db.DateTime, nullable=True)
    created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    
    # ========== روابط (با نام‌های یکتا) ==========
   
    # 1. روابط با Project
    projects_as_manager = db.relationship(
        'Project',
        foreign_keys='Project.manager_id',
        backref='manager_user',
        lazy='dynamic'
    )
    projects_as_employer = db.relationship(
        'Project',
        foreign_keys='Project.employer_id',
        backref='employer_user',
        lazy='dynamic'
    )
    created_projects = db.relationship(
        'Project',
        foreign_keys='Project.created_by',
        backref='creator_user',
        lazy='dynamic'
    )
    
    # 2. روابط با ProjectEmployee
    project_employees = db.relationship(
        'ProjectEmployee',
        foreign_keys='ProjectEmployee.employee_id',
        backref='user',
        lazy='dynamic'
    )
    
    # 4. روابط با Contract - با نام‌های یکتا
    contracts = db.relationship(
        'Contract',
        foreign_keys='Contract.employee_id',
        backref='user_contracts',
        lazy='dynamic'
    )
    created_contracts = db.relationship(
        'Contract',
        foreign_keys='Contract.created_by',
        backref='user_created_contracts',
        lazy='dynamic'
    )
    
    # 5. روابط با Notification - با نام یکتا
    notifications = db.relationship(
        'Notification',
        foreign_keys='Notification.user_id',
        backref='user_notifications',
        lazy='dynamic'
    )
    
    # 6. روابط با Payment - با نام‌های یکتا
    payments_received = db.relationship(
        'Payment',
        foreign_keys='Payment.employee_id',
        backref='user_payments_received',
        lazy='dynamic'
    )
    payments_made = db.relationship(
        'Payment',
        foreign_keys='Payment.employer_id',
        backref='user_payments_made',
        lazy='dynamic'
    )
    
    # 7. روابط با Deposit
    deposits_made = db.relationship(
        'Deposit',
        foreign_keys='Deposit.employer_id',
        backref='employer_user',
        lazy='dynamic'
    )
    
    # 8. روابط با PaymentRequest - با نام‌های یکتا
    payment_requests_created = db.relationship(
        'PaymentRequest',
        foreign_keys='PaymentRequest.created_by',
        backref='user_created_requests',
        lazy='dynamic'
    )
    payment_requests_approved_manager = db.relationship(
        'PaymentRequest',
        foreign_keys='PaymentRequest.manager_approved_by',
        backref='manager_approved_requests',
        lazy='dynamic'
    )
    payment_requests_approved_employer = db.relationship(
        'PaymentRequest',
        foreign_keys='PaymentRequest.employer_approved_by',
        backref='employer_approved_requests',
        lazy='dynamic'
    )
    payment_requests_approved_admin = db.relationship(
        'PaymentRequest',
        foreign_keys='PaymentRequest.admin_approved_by',
        backref='admin_approved_requests',
        lazy='dynamic'
    )
    
    # 9. روابط با PhotoReport
    photo_reports = db.relationship(
        'PhotoReport',
        foreign_keys='PhotoReport.employee_id',
        backref='employee_user',
        lazy='dynamic'
    )
    
    # 10. روابط با AuditLog
    audit_logs = db.relationship(
        'AuditLog',
        foreign_keys='AuditLog.user_id',
        backref='user_audit_logs',
        lazy='dynamic'
    )
    
    # 11. روابط با ElectronicCheck
    checks_issued = db.relationship(
        'ElectronicCheck',
        foreign_keys='ElectronicCheck.issued_by',
        backref='issuer_user',
        lazy='dynamic'
    )
    
    # 12. روابط با BankCheck
    bank_checks_allocated = db.relationship(
        'BankCheck',
        foreign_keys='BankCheck.allocated_by',
        backref='allocator_user',
        lazy='dynamic'
    )
    
    # 13. روابط با BankCheckBook
    check_books_created = db.relationship(
        'BankCheckBook',
        foreign_keys='BankCheckBook.created_by',
        backref='creator_user',
        lazy='dynamic'
    )
    
    escrow_deposits = db.relationship(
        'EscrowTransaction',
        foreign_keys='EscrowTransaction.employer_id',
        backref='depositor_user',
        lazy='dynamic'
    )
    escrow_withdrawals = db.relationship(
        'EscrowTransaction',
        foreign_keys='EscrowTransaction.employee_id',
        backref='withdrawer_user',
        lazy='dynamic'
    )
    # تغییر نام این رابطه
    escrow_transactions_created = db.relationship(
        'EscrowTransaction',
        foreign_keys='EscrowTransaction.created_by',
        backref='escrow_transactions_created_by_ref',  # تغییر نام
        lazy='dynamic'
    )
    
    # 15. روابط با SystemCommission
    manager_commissions = db.relationship(
        'SystemCommission',
        foreign_keys='SystemCommission.manager_id',
        backref='manager_user',
        lazy='dynamic'
    )
    
    # 16. روابط برای created_by و manager_approved_by
    creator = db.relationship(
        'User',
        remote_side=[id],
        foreign_keys=[created_by],
        backref='created_users',
        lazy='select'
    )
    
    approved_by_user = db.relationship(
        'User',
        remote_side=[id],
        foreign_keys=[manager_approved_by],
        backref='approved_users',
        lazy='select'
    )
    
    # ========== ویژگی‌های جدید برای مدیریت نقش‌ها ==========
    
    @property
    def roles(self):
        """دریافت لیست نقش‌های کاربر"""
        try:
            return json.loads(self._roles) if self._roles else ['employee']
        except:
            return ['employee']
    
    @roles.setter
    def roles(self, roles_list):
        """تنظیم لیست نقش‌های کاربر"""
        if isinstance(roles_list, list) and roles_list:
            self._roles = json.dumps(roles_list)
            # تنظیم نقش اصلی به عنوان اولین نقش
            self.role = roles_list[0]
        elif isinstance(roles_list, list):
            self._roles = '["employee"]'
            self.role = 'employee'
    
    def has_role(self, role_name):
        """بررسی وجود یک نقش خاص"""
        return role_name in self.roles
    
    def add_role(self, role_name):
        """افزودن نقش جدید"""
        if role_name not in self.roles:
            roles = self.roles
            roles.append(role_name)
            self.roles = roles
            return True
        return False
    
    def remove_role(self, role_name):
        """حذف یک نقش"""
        if role_name in self.roles and len(self.roles) > 1:
            roles = self.roles
            roles.remove(role_name)
            self.roles = roles
            return True
        return False
    
    def get_primary_role(self):
        """دریافت نقش اصلی"""
        roles = self.roles
        return roles[0] if roles else 'employee'
    
    @property
    def roles_display(self):
        """نمایش نقش‌ها به فارسی"""
        role_names = {
            'admin': 'مدیر سیستم',
            'manager': 'مدیر پروژه',
            'employer': 'کارفرما',
            'employee': 'عامل اجرایی',
            'supervisor': 'ناظر'
        }
        return [role_names.get(r, r) for r in self.roles]
    
    # ========== پراپرتی‌های سازگاری با کدهای قدیمی ==========
    
    @property
    def is_admin(self):
        return 'admin' in self.roles
    
    @property
    def is_manager(self):
        return 'manager' in self.roles
    
    @property
    def is_employer(self):
        return 'employer' in self.roles
    
    @property
    def is_employee(self):
        return 'employee' in self.roles
    
    @property
    def is_supervisor(self):
        return 'supervisor' in self.roles
    
    @property
    def display_role(self):
        """نمایش نقش اصلی به فارسی"""
        roles_map = {
            'admin': 'مدیر سیستم',
            'manager': 'مدیر پروژه',
            'employer': 'کارفرما',
            'employee': 'عامل اجرایی',
            'supervisor': 'ناظر'
        }
        return roles_map.get(self.role, self.role)
    
    @property
    def full_name(self):
        return self.fullname
    
    # ========== متدهای مدیریت پروژه‌ها ==========
    
    def get_project_role(self, project_id):
        """دریافت نقش کاربر در یک پروژه خاص"""
        from app.models import Project, ProjectEmployee
        
        project = Project.query.get(project_id)
        if not project:
            return None
        
        # اگر کاربر در پروژه به عنوان مدیر ثبت شده باشد
        if project.manager_id == self.id:
            return 'manager'
        
        # اگر کاربر در پروژه به عنوان کارفرما ثبت شده باشد
        if project.employer_id == self.id:
            return 'employer'
        
        # اگر کاربر در پروژه به عنوان کارمند/ناظر ثبت شده باشد
        project_employee = ProjectEmployee.query.filter_by(
            project_id=project_id,
            employee_id=self.id,
            is_active=True
        ).first()
        
        if project_employee:
            return project_employee.role_type
        
        return None
    
    def get_projects_with_roles(self):
        """دریافت تمام پروژه‌ها با نقش کاربر"""
        from app.models import Project, ProjectEmployee
        
        result = []
        
        # پروژه‌هایی که کاربر مدیر است
        manager_projects = Project.query.filter_by(manager_id=self.id).all()
        for p in manager_projects:
            result.append({'project': p, 'role': 'manager'})
        
        # پروژه‌هایی که کاربر کارفرما است
        employer_projects = Project.query.filter_by(employer_id=self.id).all()
        for p in employer_projects:
            result.append({'project': p, 'role': 'employer'})
        
        # پروژه‌هایی که کاربر کارمند/ناظر است
        project_employees = ProjectEmployee.query.filter_by(
            employee_id=self.id,
            is_active=True
        ).all()
        for pe in project_employees:
            result.append({'project': pe.project, 'role': pe.role_type})
        
        return result
    
    # ========== متدهای اصلی ==========
    
    def set_password(self, password):
        self.password_hash = generate_password_hash(password)
    
    def check_password(self, password):
        return check_password_hash(self.password_hash, password)
    
    def set_temp_password(self, password, expiry_minutes=5):
        from datetime import timedelta
        self.temp_password = password
        self.temp_password_expires = datetime.utcnow() + timedelta(minutes=expiry_minutes)
        self.is_temp_password = True
    
    def verify_temp_password(self, password):
        if not self.temp_password or self.temp_password != password:
            return False
        if self.temp_password_expires and self.temp_password_expires < datetime.utcnow():
            return False
        return True
    
    def set_face_encoding(self, encoding_data):
        if hasattr(encoding_data, 'tolist'):
            encoding_data = encoding_data.tolist()
        elif isinstance(encoding_data, np.ndarray):
            encoding_data = encoding_data.tolist()
        
        encoding_json = json.dumps(encoding_data)
        self.face_encoding = base64.b64encode(encoding_json.encode('utf-8')).decode('utf-8')
        self.face_verified_at = datetime.utcnow()
    
    def get_face_encoding(self):
        if not self.face_encoding:
            return None
        try:
            decoded = base64.b64decode(self.face_encoding).decode('utf-8')
            face_encoding = json.loads(decoded)
            return np.array(face_encoding)
        except Exception:
            return None
    
    def has_face_encoding(self):
        return self.face_encoding is not None and len(self.face_encoding) > 0
    
    def get_employee_projects(self):
        from app.models import Project, ProjectEmployee
        return Project.query.join(ProjectEmployee).filter(
            ProjectEmployee.employee_id == self.id
        ).all()
    
    def get_id(self):
        return str(self.id)
    
    def __repr__(self):
        return f'<User {self.username} - Roles: {self.roles}>'


@login_manager.user_loader
def load_user(user_id):
    try:
        return User.query.get(int(user_id))
    except (ValueError, TypeError):
        return None