# app/models/check.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 random
import string


class ElectronicCheck(db.Model):
    """مدل چک الکترونیک"""
    __tablename__ = 'electronic_checks'
    __table_args__ = {'extend_existing': True}
    
    id = db.Column(db.Integer, primary_key=True)
    check_number = db.Column(db.String(50), unique=True, nullable=False)
    payment_request_id = db.Column(db.Integer, db.ForeignKey('payment_requests.id'), unique=True, nullable=True)
    
    # اطلاعات چک
    amount = db.Column(db.Float, nullable=False)
    recipient_name = db.Column(db.String(100), nullable=False)
    recipient_phone = db.Column(db.String(20), nullable=True)
    recipient_national_code = db.Column(db.String(10), nullable=True)
    
    # تاریخ‌ها
    issue_date = db.Column(db.DateTime, default=datetime.utcnow)
    due_date = db.Column(db.DateTime, nullable=False)
    
    # وضعیت
    status = db.Column(db.String(20), default='issued')  # issued, active, cashed, cancelled, expired
    
    # اطلاعات بانکی
    bank_name = db.Column(db.String(100), nullable=True)
    account_number = db.Column(db.String(50), nullable=True)
    
    # تاییدات
    signed_by_admin = db.Column(db.Boolean, default=False)
    signed_at = db.Column(db.DateTime, nullable=True)
    
    # توضیحات
    description = db.Column(db.Text, nullable=True)
    
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    issued_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    
    # ========== روابط با نام‌های یکتا ==========
    
    # رابطه با PaymentRequest
    payment_request = db.relationship(
        'PaymentRequest',
        foreign_keys=[payment_request_id],
        backref='electronic_check_ref',  # نام یکتا
        uselist=False
    )
    
    # رابطه با Issuer (User)
    issuer = db.relationship(
        'User',
        foreign_keys=[issued_by],
        backref='issued_checks_list'  # نام یکتا
    )
    
    # رابطه با CheckTransaction
    check_transactions = db.relationship(
        'CheckTransaction',
        foreign_keys='CheckTransaction.check_id',
        backref='check_reference',  # نام یکتا
        lazy='dynamic'
    )
    
    # ========== متدها ==========
    
    def generate_check_number(self):
        """تولید شماره چک الکترونیک منحصر به فرد"""
        import hashlib
        import random
        code_string = f"{self.recipient_name}{self.amount}{datetime.now().timestamp()}{random.randint(1000, 9999)}"
        self.check_number = hashlib.md5(code_string.encode()).hexdigest()[:16].upper()
        return self.check_number
    
    def issue(self, admin_id):
        """صدور چک توسط ادمین"""
        self.status = 'issued'
        self.issued_by = admin_id
        self.issue_date = datetime.utcnow()
        self.signed_by_admin = True
        self.signed_at = datetime.utcnow()
        
        # ثبت تراکنش
        from app.models import CheckTransaction
        CheckTransaction.log_issue(
            check_id=self.id,
            amount=self.amount,
            performed_by=admin_id,
            description=f'صدور چک برای {self.recipient_name}'
        )
    
    def activate(self, admin_id):
        """فعالسازی چک"""
        self.status = 'active'
        
        # ثبت تراکنش
        from app.models import CheckTransaction
        CheckTransaction.log_activate(
            check_id=self.id,
            performed_by=admin_id
        )
    
    def cancel(self, admin_id, reason=None):
        """ابطال چک"""
        self.status = 'cancelled'
        
        # ثبت تراکنش
        from app.models import CheckTransaction
        CheckTransaction.log_cancel(
            check_id=self.id,
            performed_by=admin_id,
            reason=reason
        )
    
    def mark_as_cashed(self, admin_id):
        """نقد شدن چک"""
        self.status = 'cashed'
        
        # ثبت تراکنش
        from app.models import CheckTransaction
        CheckTransaction.log_cash(
            check_id=self.id,
            performed_by=admin_id
        )
    
    def is_expired(self):
        """بررسی انقضای چک"""
        return datetime.utcnow() > self.due_date
    
    def get_status_display(self):
        """نمایش وضعیت به فارسی"""
        status_map = {
            'issued': 'صادر شده',
            'active': 'فعال',
            'cashed': 'نقد شده',
            'cancelled': 'ابطال شده',
            'expired': 'منقضی شده'
        }
        return status_map.get(self.status, self.status)
    
    def to_dict(self):
        """تبدیل به دیکشنری برای JSON"""
        return {
            'id': self.id,
            'check_number': self.check_number,
            'amount': self.amount,
            'amount_formatted': f"{self.amount:,.0f}",
            'recipient_name': self.recipient_name,
            'recipient_phone': self.recipient_phone,
            'issue_date': self.issue_date.strftime('%Y-%m-%d %H:%M:%S'),
            'due_date': self.due_date.strftime('%Y-%m-%d %H:%M:%S'),
            'status': self.status,
            'status_display': self.get_status_display(),
            'bank_name': self.bank_name,
            'description': self.description,
            'is_expired': self.is_expired()
        }
    
    def __repr__(self):
        return f'<ElectronicCheck {self.check_number} - {self.amount}>'


class BankCheckBook(db.Model):
    """دفترچه چک بانکی - حساب سامانه"""
    __tablename__ = 'bank_check_books'
    __table_args__ = {'extend_existing': True}
    
    id = db.Column(db.Integer, primary_key=True)
    system_account_id = db.Column(db.Integer, db.ForeignKey('system_bank_accounts.id'), nullable=False)
    
    # محدوده شماره چک‌ها
    start_number = db.Column(db.String(50), nullable=False)
    end_number = db.Column(db.String(50), nullable=False)
    current_number = db.Column(db.String(50), nullable=False)
    
    # آمار
    total_checks = db.Column(db.Integer, default=0)
    used_checks = db.Column(db.Integer, default=0)
    remaining_checks = db.Column(db.Integer, default=0)
    
    # وضعیت
    status = db.Column(db.String(20), default='active')  # active, completed, cancelled
    
    # تاریخ‌ها
    received_date = db.Column(db.Date, nullable=False)
    expiry_date = db.Column(db.Date, nullable=True)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    
    # ========== روابط با نام‌های یکتا ==========
    
    # رابطه با SystemBankAccount
    system_account = db.relationship(
        'SystemBankAccount',
        foreign_keys=[system_account_id],
        backref='bank_check_books_list'  # نام یکتا
    )
    
    # رابطه با Creator (User)
    creator = db.relationship(
        'User',
        foreign_keys=[created_by],
        backref='created_check_books_list'  # نام یکتا
    )
    
    # رابطه با BankCheck
    checks = db.relationship(
        'BankCheck',
        backref='check_book_ref',  # نام یکتا
        lazy=True
    )
    
    # ========== متدها ==========
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.calculate_counts()
    
    def calculate_counts(self):
        """محاسبه تعداد کل و باقیمانده چک‌ها"""
        if self.start_number and self.end_number:
            try:
                start = int(self.start_number)
                end = int(self.end_number)
                self.total_checks = end - start + 1
                self.remaining_checks = self.total_checks - self.used_checks
            except ValueError:
                pass
    
    def get_next_check_number(self):
        """دریافت شماره چک بعدی"""
        if self.remaining_checks <= 0:
            return None
        return str(int(self.current_number))
    
    def use_check(self, check_number):
        """استفاده از یک چک"""
        if self.remaining_checks > 0 and check_number == self.current_number:
            self.used_checks += 1
            self.remaining_checks -= 1
            self.current_number = str(int(self.current_number) + 1)
            
            if self.remaining_checks == 0:
                self.status = 'completed'
            return True
        return False
    
    def get_available_checks(self):
        """دریافت لیست چک‌های موجود"""
        return BankCheck.query.filter_by(
            check_book_id=self.id,
            status='available'
        ).all()
    
    def get_used_checks(self):
        """دریافت لیست چک‌های استفاده شده"""
        return BankCheck.query.filter_by(
            check_book_id=self.id
        ).filter(BankCheck.status.in_(['allocated', 'used'])).all()
    
    def to_dict(self):
        """تبدیل به دیکشنری برای JSON"""
        return {
            'id': self.id,
            'bank_name': self.system_account.bank_name if self.system_account else None,
            'account_number': self.system_account.account_number if self.system_account else None,
            'start_number': self.start_number,
            'end_number': self.end_number,
            'current_number': self.current_number,
            'total_checks': self.total_checks,
            'used_checks': self.used_checks,
            'remaining_checks': self.remaining_checks,
            'status': self.status,
            'received_date': self.received_date.strftime('%Y-%m-%d'),
            'expiry_date': self.expiry_date.strftime('%Y-%m-%d') if self.expiry_date else None
        }
    
    def __repr__(self):
        return f'<BankCheckBook {self.system_account.bank_name if self.system_account else "Unknown"} - {self.start_number} to {self.end_number}>'


class BankCheck(db.Model):
    """چک‌های بانکی حساب سامانه"""
    __tablename__ = 'bank_checks'
    __table_args__ = {'extend_existing': True}
    
    id = db.Column(db.Integer, primary_key=True)
    check_book_id = db.Column(db.Integer, db.ForeignKey('bank_check_books.id'), nullable=False)
    
    check_number = db.Column(db.String(50), nullable=False)
    serial_number = db.Column(db.String(50), unique=True, nullable=False)
    
    # وضعیت
    status = db.Column(db.String(20), default='available')  # available, allocated, used, cancelled, returned
    
    # اختصاص به تراکنش
    allocated_to_payment_id = db.Column(db.Integer, db.ForeignKey('payment_requests.id'), nullable=True)
    allocated_at = db.Column(db.DateTime, nullable=True)
    allocated_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    
    # اطلاعات صادر شده
    issued_to = db.Column(db.String(100), nullable=True)  # گیرنده چک
    issued_amount = db.Column(db.Float, nullable=True)
    issue_date = db.Column(db.Date, nullable=True)
    
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # ========== روابط با نام‌های یکتا ==========
    
    # رابطه با BankCheckBook
    check_book = db.relationship(
        'BankCheckBook',
        foreign_keys=[check_book_id],
        backref='bank_checks_list'  # نام یکتا
    )
    
    # رابطه با PaymentRequest
    payment_request = db.relationship(
        'PaymentRequest',
        foreign_keys=[allocated_to_payment_id],
        backref='bank_check_ref'  # نام یکتا
    )
    
    # رابطه با Allocator (User)
    allocator = db.relationship(
        'User',
        foreign_keys=[allocated_by],
        backref='allocated_bank_checks_list'  # نام یکتا
    )
    
    # رابطه با CheckTransaction
    check_transactions = db.relationship(
        'CheckTransaction',
        foreign_keys='CheckTransaction.bank_check_id',
        backref='bank_check_reference',  # نام یکتا
        lazy='dynamic'
    )
    
    # ========== متدها ==========
    
    def allocate_to_payment(self, payment_request_id, user_id):
        """اختصاص چک به درخواست پرداخت"""
        if self.status == 'available':
            self.status = 'allocated'
            self.allocated_to_payment_id = payment_request_id
            self.allocated_at = datetime.utcnow()
            self.allocated_by = user_id
            
            # بروزرسانی دفترچه چک
            self.check_book.use_check(self.check_number)
            
            # ثبت تراکنش
            from app.models import CheckTransaction
            CheckTransaction.log_allocate(
                check_id=None,
                bank_check_id=self.id,
                performed_by=user_id,
                description=f'اختصاص چک شماره {self.check_number} به درخواست {payment_request_id}'
            )
            return True
        return False
    
    def mark_as_used(self):
        """علامت زدن چک به عنوان استفاده شده"""
        self.status = 'used'
    
    def mark_as_cancelled(self, user_id, reason=None):
        """ابطال چک"""
        self.status = 'cancelled'
        
        # ثبت تراکنش
        from app.models import CheckTransaction
        CheckTransaction.log_cancel(
            check_id=None,
            performed_by=user_id,
            reason=reason,
            description=f'ابطال چک شماره {self.check_number}'
        )
    
    def mark_as_returned(self, user_id, reason=None):
        """بازگشت چک به بانک"""
        self.status = 'returned'
        
        # ثبت تراکنش
        from app.models import CheckTransaction
        CheckTransaction.log_return(
            bank_check_id=self.id,
            performed_by=user_id,
            reason=reason
        )
    
    def get_status_display(self):
        """نمایش وضعیت به فارسی"""
        status_map = {
            'available': 'موجود',
            'allocated': 'اختصاص داده شده',
            'used': 'استفاده شده',
            'cancelled': 'ابطال شده',
            'returned': 'بازگشت به بانک'
        }
        return status_map.get(self.status, self.status)
    
    def to_dict(self):
        """تبدیل به دیکشنری برای JSON"""
        return {
            'id': self.id,
            'check_number': self.check_number,
            'serial_number': self.serial_number,
            'status': self.status,
            'status_display': self.get_status_display(),
            'allocated_to_payment_id': self.allocated_to_payment_id,
            'allocated_at': self.allocated_at.strftime('%Y-%m-%d %H:%M:%S') if self.allocated_at else None,
            'allocator_name': self.allocator.fullname if self.allocator else None,
            'issued_to': self.issued_to,
            'issued_amount': self.issued_amount,
            'issue_date': self.issue_date.strftime('%Y-%m-%d') if self.issue_date else None,
            'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S')
        }
    
    def __repr__(self):
        return f'<BankCheck {self.check_number} - {self.status}>'