# app/models/payment.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
import hashlib


class PaymentType:
    """انواع پرداخت"""
    MONTHLY = 'monthly'      # ماهیانه
    INSTALLMENT = 'installment'  # اقساطی
    FULL = 'full'            # یکجا


class PaymentStatus:
    """وضعیت پرداخت"""
    PENDING = 'pending'      # در انتظار
    APPROVED = 'approved'    # تایید شده
    PAID = 'paid'           # پرداخت شده
    REJECTED = 'rejected'   # رد شده
    CANCELLED = 'cancelled' # لغو شده


class Payment(db.Model):
    """مدل پرداخت"""
    __tablename__ = 'payments'
    
    id = db.Column(db.Integer, primary_key=True)
    project_id = db.Column(db.Integer, db.ForeignKey('projects.id'), nullable=False)
    employee_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    employer_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    payment_request_id = db.Column(db.Integer, db.ForeignKey('payment_requests.id'), nullable=True)
    
    # اضافه کردن فیلد برای ارتباط با PaymentIdentifier
    payment_identifier_id = db.Column(db.Integer, db.ForeignKey('payment_identifiers.id'), nullable=True)
    
    amount = db.Column(db.BigInteger, nullable=False)
    installment_number = db.Column(db.Integer, nullable=True)
    payment_method = db.Column(db.String(50), nullable=False)  # cash, check, transfer
    check_number = db.Column(db.String(50), nullable=True)
    check_due_date = db.Column(db.Date, nullable=True)
    bank_name = db.Column(db.String(100), nullable=True)
    tracking_code = db.Column(db.String(100), nullable=True)
    payment_date = db.Column(db.Date, nullable=False)
    status = db.Column(db.String(20), default='pending')  # pending, paid, failed
    
    # فیلدهای سیستمی
    recorded_by = db.Column(db.Integer, db.ForeignKey('users.id'))
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # روابط
    project = db.relationship('Project', backref='payments')
    employee = db.relationship('User', foreign_keys=[employee_id])
    recorder = db.relationship('User', foreign_keys=[recorded_by])
    
    # رابطه با PaymentIdentifier (با مشخص کردن primaryjoin)
    payment_identifier = db.relationship(
        'PaymentIdentifier', 
        foreign_keys=[payment_identifier_id],
        back_populates='payments'
    )


class PaymentIdentifier(db.Model):
    """مدل کد شناسه پرداخت"""
    __tablename__ = 'payment_identifiers'
    
    id = db.Column(db.Integer, primary_key=True)
    identifier_code = db.Column(db.String(20), unique=True, nullable=False)
    contract_id = db.Column(db.Integer, db.ForeignKey('contracts.id'), nullable=False)
    installment_id = db.Column(db.Integer, db.ForeignKey('contract_installments.id'), nullable=True)
    
    amount = db.Column(db.BigInteger, nullable=False)
    due_date = db.Column(db.Date, nullable=False)
    payment_type = db.Column(db.String(20), nullable=False)  # installment, full, advance
    
    status = db.Column(db.String(20), default='pending')  # pending, paid, cancelled, expired
    is_active = db.Column(db.Boolean, default=True)
    
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    paid_at = db.Column(db.DateTime, nullable=True)
    cancelled_at = db.Column(db.DateTime, nullable=True)
    
    notified_employer = db.Column(db.Boolean, default=False)
    notified_at = db.Column(db.DateTime, nullable=True)
    
    # روابط
    contract = db.relationship('Contract', backref='payment_identifiers')
    installment = db.relationship('ContractInstallment', backref='payment_identifiers')
    
    # رابطه با Payment (با مشخص کردن back_populates)
    payments = db.relationship(
        'Payment',
        foreign_keys=[Payment.payment_identifier_id],
        back_populates='payment_identifier',
        lazy='dynamic'
    )
    
    # رابطه با CheckIssuance
    check_issuances = db.relationship(
        'CheckIssuance',
        foreign_keys='CheckIssuance.payment_identifier_id',
        backref='payment_identifier',
        lazy='dynamic'
    )
    
    # رابطه با PaymentControl
    controls = db.relationship(
        'PaymentControl',
        foreign_keys='PaymentControl.payment_identifier_id',
        backref='payment_identifier',
        lazy='dynamic'
    )
    
    def generate_identifier_code(self):
        """تولید کد شناسه یکتا 16 رقمی با فرمت: PID-YYYYMMDD-XXXX"""
        import random
        import string
        from datetime import datetime
        
        date_part = datetime.now().strftime('%Y%m%d')
        random_part = ''.join(random.choices(string.digits, k=6))
        code = f"PID-{date_part}-{random_part}"
        
        while PaymentIdentifier.query.filter_by(identifier_code=code).first():
            random_part = ''.join(random.choices(string.digits, k=6))
            code = f"PID-{date_part}-{random_part}"
        
        return code
    
    def __repr__(self):
        return f'<PaymentIdentifier {self.identifier_code}>'


class CheckIssuance(db.Model):
    """مدل صدور چک"""
    __tablename__ = 'check_issuances'
    
    id = db.Column(db.Integer, primary_key=True)
    check_number = db.Column(db.String(50), nullable=False)
    payment_identifier_id = db.Column(db.Integer, db.ForeignKey('payment_identifiers.id'), nullable=False)
    
    amount = db.Column(db.BigInteger, nullable=False)
    issue_date = db.Column(db.Date, nullable=False)
    due_date = db.Column(db.Date, nullable=False)
    bank_name = db.Column(db.String(100), nullable=False)
    account_number = db.Column(db.String(50), nullable=False)
    
    recipient_type = db.Column(db.String(20), nullable=False)  # employer, employee
    recipient_id = db.Column(db.Integer, nullable=False)
    
    status = db.Column(db.String(20), default='issued')  # issued, cashed, returned, cancelled
    is_active = db.Column(db.Boolean, default=True)
    
    issued_at = db.Column(db.DateTime, default=datetime.utcnow)
    cashed_at = db.Column(db.DateTime, nullable=True)
    returned_at = db.Column(db.DateTime, nullable=True)
    
    issued_by = db.Column(db.Integer, db.ForeignKey('users.id'))
    cashed_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    
    description = db.Column(db.Text, nullable=True)
    reference_number = db.Column(db.String(50), nullable=True)
    
    # روابط
    issuer = db.relationship('User', foreign_keys=[issued_by])
    casher = db.relationship('User', foreign_keys=[cashed_by])
    
    def __repr__(self):
        return f'<CheckIssuance {self.check_number}>'


class PaymentControl(db.Model):
    """مدل کنترل پرداخت"""
    __tablename__ = 'payment_controls'
    
    id = db.Column(db.Integer, primary_key=True)
    payment_identifier_id = db.Column(db.Integer, db.ForeignKey('payment_identifiers.id'), nullable=False)
    
    control_stage = db.Column(db.String(20), nullable=False)  # employer_approval, manager_approval, admin_approval, payment_execution
    
    status = db.Column(db.String(20), default='pending')  # pending, approved, rejected, executed
    
    approver_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    reviewer_id = 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)
    approved_at = db.Column(db.DateTime, nullable=True)
    
    comment = db.Column(db.Text, nullable=True)
    
    # روابط
    approver = db.relationship('User', foreign_keys=[approver_id])
    reviewer = db.relationship('User', foreign_keys=[reviewer_id])
    
    def __repr__(self):
        return f'<PaymentControl {self.payment_identifier_id} - {self.control_stage}>'
    


class PaymentRequest(db.Model):
    """مدل درخواست پرداخت"""
    __tablename__ = 'payment_requests'
    __table_args__ = {'extend_existing': True}
    
    id = db.Column(db.Integer, primary_key=True)
    
    # روابط کلیدی
    contract_id = db.Column(db.Integer, db.ForeignKey('contracts.id'), nullable=False)
    installment_id = db.Column(db.Integer, db.ForeignKey('contract_installments.id'), nullable=True)
    deposit_id = db.Column(db.Integer, db.ForeignKey('deposits.id'), nullable=True)
    
    # اطلاعات درخواست
    request_number = db.Column(db.String(50), unique=True, nullable=False)
    amount = db.Column(db.Float, nullable=False)
    request_date = db.Column(db.Date, nullable=False)
    due_date = db.Column(db.Date, nullable=False)
    
    # مراحل تایید - Manager
    manager_approved = db.Column(db.Boolean, default=False)
    manager_approved_at = db.Column(db.DateTime, nullable=True)
    manager_approved_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    
    # مراحل تایید - Employer
    employer_approved = db.Column(db.Boolean, default=False)
    employer_approved_at = db.Column(db.DateTime, nullable=True)
    employer_approved_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    
    # مراحل تایید - Admin
    admin_approved = db.Column(db.Boolean, default=False)
    admin_approved_at = db.Column(db.DateTime, nullable=True)
    admin_approved_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    
    # وضعیت نهایی
    status = db.Column(db.String(20), default='pending')  # pending, approved, rejected, paid
    
    # اطلاعات چک الکترونیک
    electronic_check_id = db.Column(db.Integer, db.ForeignKey('electronic_checks.id'), nullable=True)
    
    # توضیحات
    description = db.Column(db.Text, nullable=True)
    rejection_reason = db.Column(db.Text, nullable=True)
    
    # زمان‌ها
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    paid_at = db.Column(db.DateTime, nullable=True)
    
    # ========== روابط با نام‌های یکتا ==========
    
    # رابطه با Contract
    source_contract = db.relationship(
        'Contract',
        foreign_keys=[contract_id],
        backref='payment_requests_list'
    )
    
    # رابطه با ContractInstallment
    installment = db.relationship(
        'ContractInstallment',
        foreign_keys=[installment_id],
        backref='payment_requests_list'
    )
    
    # رابطه با Deposit
    deposit = db.relationship(
        'Deposit',
        foreign_keys=[deposit_id],
        backref='payment_requests_list'
    )
    
    # رابطه با User (Manager Approver)
    manager_approver = db.relationship(
        'User',
        foreign_keys=[manager_approved_by],
        backref='approved_payment_requests_manager'
    )
    
    # رابطه با User (Employer Approver)
    employer_approver = db.relationship(
        'User',
        foreign_keys=[employer_approved_by],
        backref='approved_payment_requests_employer'
    )
    
    # رابطه با User (Admin Approver)
    admin_approver = db.relationship(
        'User',
        foreign_keys=[admin_approved_by],
        backref='approved_payment_requests_admin'
    )
    
    # رابطه با User (Creator)
    creator = db.relationship(
        'User',
        foreign_keys=[created_by],
        backref='created_payment_requests'
    )
    
    # رابطه با ElectronicCheck
    electronic_check = db.relationship(
        'ElectronicCheck',
        foreign_keys=[electronic_check_id],
        backref='payment_request_ref'
    )
    
    # رابطه با Payment
    payment = db.relationship(
        'Payment',
        foreign_keys='Payment.payment_request_id',
        backref='payment_request_ref'
    )
    
    # ========== حذف رابطه مشکل‌دار ==========
    # approvals = db.relationship('ApprovalWorkflow', ...) - حذف شود
    
    # ========== Propertyهای جایگزین ==========
    
    @property
    def approvals_list(self):
        """دریافت تمام گام‌های تایید مرتبط با این درخواست"""
        from app.models import ApprovalWorkflow
        return ApprovalWorkflow.query.filter_by(payment_release_id=self.id).all()
    
    @property
    def pending_approvals(self):
        """دریافت گام‌های تایید در انتظار"""
        from app.models import ApprovalWorkflow
        return ApprovalWorkflow.query.filter_by(
            payment_release_id=self.id,
            status='pending'
        ).all()
    
    @property
    def approved_approvals(self):
        """دریافت گام‌های تایید شده"""
        from app.models import ApprovalWorkflow
        return ApprovalWorkflow.query.filter_by(
            payment_release_id=self.id,
            status='approved'
        ).all()
    
    @property
    def rejected_approvals(self):
        """دریافت گام‌های تایید رد شده"""
        from app.models import ApprovalWorkflow
        return ApprovalWorkflow.query.filter_by(
            payment_release_id=self.id,
            status='rejected'
        ).all()
    
    @property
    def is_fully_approved(self):
        """بررسی تایید کامل"""
        approvals = self.approvals_list
        if not approvals:
            return False
        return all(a.status == 'approved' for a in approvals)
    
    @property
    def is_any_rejected(self):
        """بررسی وجود رد"""
        approvals = self.approvals_list
        return any(a.status == 'rejected' for a in approvals)
    
    @property
    def approval_progress(self):
        """دریافت پیشرفت تایید"""
        approvals = self.approvals_list
        if not approvals:
            return 0
        approved_count = sum(1 for a in approvals if a.status == 'approved')
        return int((approved_count / len(approvals)) * 100)
    
    # ========== متدها ==========
    
    def generate_request_number(self):
        """تولید شماره درخواست یکتا"""
        import hashlib
        code_string = f"{self.contract_id}{self.amount}{datetime.now().timestamp()}"
        self.request_number = hashlib.md5(code_string.encode()).hexdigest()[:12].upper()
        return self.request_number
    
    def approve_manager(self, user_id):
        """تایید توسط مدیر پروژه"""
        self.manager_approved = True
        self.manager_approved_at = datetime.utcnow()
        self.manager_approved_by = user_id
        self._check_approvals()
    
    def approve_employer(self, user_id):
        """تایید توسط کارفرما"""
        self.employer_approved = True
        self.employer_approved_at = datetime.utcnow()
        self.employer_approved_by = user_id
        self._check_approvals()
    
    def approve_admin(self, user_id):
        """تایید نهایی توسط ادمین"""
        self.admin_approved = True
        self.admin_approved_at = datetime.utcnow()
        self.admin_approved_by = user_id
        self._check_approvals()
    
    def _check_approvals(self):
        """بررسی تاییدات و تغییر وضعیت"""
        if self.manager_approved and self.employer_approved and self.admin_approved:
            self.status = 'approved'
    
    def reject(self, user_id, reason=None):
        """رد درخواست"""
        self.status = 'rejected'
        if reason:
            self.rejection_reason = reason
    
    def mark_as_paid(self, user_id=None):
        """علامت زدن به عنوان پرداخت شده"""
        self.status = 'paid'
        self.paid_at = datetime.utcnow()
    
    def get_status_display(self):
        """نمایش وضعیت به فارسی"""
        status_map = {
            'pending': 'در انتظار',
            'approved': 'تایید شده',
            'rejected': 'رد شده',
            'paid': 'پرداخت شده'
        }
        return status_map.get(self.status, self.status)
    
    def get_approval_status(self):
        """دریافت وضعیت تاییدات"""
        return {
            'manager': self.manager_approved,
            'employer': self.employer_approved,
            'admin': self.admin_approved
        }
    
    def to_dict(self):
        """تبدیل به دیکشنری برای JSON"""
        return {
            'id': self.id,
            'request_number': self.request_number,
            'contract_id': self.contract_id,
            'amount': self.amount,
            'amount_formatted': f"{self.amount:,.0f}",
            'request_date': self.request_date.strftime('%Y-%m-%d'),
            'due_date': self.due_date.strftime('%Y-%m-%d'),
            'status': self.status,
            'status_display': self.get_status_display(),
            'manager_approved': self.manager_approved,
            'employer_approved': self.employer_approved,
            'admin_approved': self.admin_approved,
            'approval_status': self.get_approval_status(),
            'approval_progress': self.approval_progress,
            'is_fully_approved': self.is_fully_approved,
            'description': self.description,
            'rejection_reason': self.rejection_reason,
            'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
            'paid_at': self.paid_at.strftime('%Y-%m-%d %H:%M:%S') if self.paid_at else None
        }
    
    def __repr__(self):
        return f'<PaymentRequest {self.request_number} - {self.amount} - {self.status}>'
    

class PaymentRelease(db.Model):
    """درخواست آزادسازی وجه از صندوق امانی"""
    __tablename__ = 'payment_releases'
    __table_args__ = {'extend_existing': True}
    
    id = db.Column(db.Integer, primary_key=True)
    
    # روابط کلیدی
    deposit_id = db.Column(db.Integer, db.ForeignKey('deposits.id'), nullable=False)
    escrow_id = db.Column(db.Integer, db.ForeignKey('escrow_accounts.id'), nullable=False)
    employee_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    contract_id = db.Column(db.Integer, db.ForeignKey('contracts.id'), nullable=False)
    
    # اطلاعات
    amount = db.Column(db.Float, nullable=False)
    release_type = db.Column(db.String(20), default='salary')  # salary, bonus, advance
    month = db.Column(db.Integer, nullable=True)
    year = db.Column(db.Integer, nullable=True)
    
    # مراحل تایید
    manager_approved = db.Column(db.Boolean, default=False)
    manager_approved_at = db.Column(db.DateTime, nullable=True)
    employer_approved = db.Column(db.Boolean, default=False)
    employer_approved_at = db.Column(db.DateTime, nullable=True)
    admin_approved = db.Column(db.Boolean, default=False)
    admin_approved_at = db.Column(db.DateTime, nullable=True)
    
    # وضعیت
    status = db.Column(db.String(20), default='pending')  # pending, approved, paid, rejected
    
    # اطلاعات چک الکترونیک
    electronic_check_id = db.Column(db.Integer, db.ForeignKey('electronic_checks.id'), nullable=True)
    
    # توضیحات
    description = db.Column(db.Text, nullable=True)
    rejection_reason = db.Column(db.Text, nullable=True)
    
    # زمان‌ها
    paid_at = db.Column(db.DateTime, nullable=True)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    created_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
    
    # ========== روابط با نام‌های یکتا ==========
    
    # رابطه با Deposit
    deposit = db.relationship(
        'Deposit',
        foreign_keys=[deposit_id],
        backref='payment_releases_list'  # نام یکتا
    )
    
    # رابطه با EscrowAccount
    escrow = db.relationship(
        'EscrowAccount',
        foreign_keys=[escrow_id],
        backref='payment_releases_list'  # نام یکتا
    )
    
    # رابطه با User (Employee)
    employee = db.relationship(
        'User',
        foreign_keys=[employee_id],
        backref='payment_releases_as_employee'  # نام یکتا
    )
    
    # رابطه با Contract
    contract = db.relationship(
        'Contract',
        foreign_keys=[contract_id],
        backref='payment_releases_list'  # نام یکتا
    )
    
    # رابطه با ElectronicCheck
    electronic_check = db.relationship(
        'ElectronicCheck',
        foreign_keys=[electronic_check_id],
        backref='payment_release_ref'  # نام یکتا
    )
    
    # رابطه با User (Creator)
    creator = db.relationship(
        'User',
        foreign_keys=[created_by],
        backref='created_payment_releases'  # نام یکتا
    )
    
    # ========== متدها ==========
    
    def approve_manager(self, user_id):
        """تایید توسط مدیر پروژه"""
        self.manager_approved = True
        self.manager_approved_at = datetime.utcnow()
        self._check_approvals()
    
    def approve_employer(self, user_id):
        """تایید توسط کارفرما"""
        self.employer_approved = True
        self.employer_approved_at = datetime.utcnow()
        self._check_approvals()
    
    def approve_admin(self, user_id):
        """تایید نهایی توسط ادمین"""
        self.admin_approved = True
        self.admin_approved_at = datetime.utcnow()
        self._check_approvals()
    
    def _check_approvals(self):
        """بررسی تاییدات و تغییر وضعیت"""
        if self.manager_approved and self.employer_approved and self.admin_approved:
            self.status = 'approved'
    
    def mark_as_paid(self, check_id=None):
        """علامت زدن به عنوان پرداخت شده"""
        self.status = 'paid'
        self.paid_at = datetime.utcnow()
        if check_id:
            self.electronic_check_id = check_id
    
    def reject(self, reason=None):
        """رد درخواست"""
        self.status = 'rejected'
        if reason:
            self.rejection_reason = reason
    
    def get_status_display(self):
        """نمایش وضعیت به فارسی"""
        status_map = {
            'pending': 'در انتظار',
            'approved': 'تایید شده',
            'paid': 'پرداخت شده',
            'rejected': 'رد شده'
        }
        return status_map.get(self.status, self.status)
    
    def to_dict(self):
        """تبدیل به دیکشنری برای JSON"""
        return {
            'id': self.id,
            'deposit_id': self.deposit_id,
            'employee_name': self.employee.fullname if self.employee else None,
            'contract_id': self.contract_id,
            'amount': self.amount,
            'amount_formatted': f"{self.amount:,.0f}",
            'release_type': self.release_type,
            'month': self.month,
            'year': self.year,
            'status': self.status,
            'status_display': self.get_status_display(),
            'manager_approved': self.manager_approved,
            'employer_approved': self.employer_approved,
            'admin_approved': self.admin_approved,
            'description': self.description,
            'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
            'paid_at': self.paid_at.strftime('%Y-%m-%d %H:%M:%S') if self.paid_at else None
        }
    
    def __repr__(self):
        return f'<PaymentRelease {self.id} - {self.amount} - {self.status}>'