from django.db import models
from humanresource.models import *
from inventory.models import *
from django.core.validators import MaxValueValidator, MinValueValidator
from django.contrib.auth.models import User

# Create your models here.


class ExpenseCategory(models.Model):
    title = models.CharField(max_length=191)
    remarks = models.TextField(blank=True, null=True)

    def __str__(self):
        return self.title


class AddExpense(models.Model):
    CASH_IN_HAND = 'C/H'
    CASH_IN_BANK = 'C/B'
    CASH_ACCOUNTS_CHOICES = [
        (CASH_IN_HAND, 'CASH IN HAND'),
        (CASH_IN_BANK, 'CASH IN BANK')

    ]
    expense_category = models.ForeignKey(
        ExpenseCategory, on_delete=models.PROTECT)
    spent_by = models.CharField(
        max_length=191, default='he')
    approved_by = models.ForeignKey(
        Employment, on_delete=models.PROTECT)
    amount = models.DecimalField(
        max_digits=10, decimal_places=2, default=0)
    currency = models.ForeignKey(
        Currency, on_delete=models.PROTECT)
    description = models.TextField(
        null=True, blank=True, default='null')
    from_account = models.CharField(
        max_length=191, choices=CASH_ACCOUNTS_CHOICES, default=CASH_IN_HAND)
    remarks = models.TextField(
        blank=True, null=True, default='null')
    date = models.DateField(null=True, blank=True)
    created_by = models.ForeignKey(
        User, on_delete=models.SET_NULL, related_name='expense_created', null=True)
    updated_by = models.ForeignKey(
        User, on_delete=models.SET_NULL, related_name='expense_updated', null=True)
    created_at = models.DateTimeField(
        auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f'{self.expense_category} - {self.amount}'
    class meta:
        permissions = [
            ('expense_report', 'Can see expense report?'),
            ('client_cash_report', 'Can see clients cash report?'),
            ('print_expense_slip', 'Can print expense Slip?'),
            ]
    def save(self, *args, **kwargs):

        from finance.models import CashAccount

        super().save(*args, **kwargs)
# --------------------------------------------------------------------------------
#                       Cash Account Related codes
        # Calculate the debit and credit amounts
        amount_in = 0
        amount_out = self.amount
        currency_instance = Currency.objects.first()
        current_date = date.today()

        # Retrieve the previous balance
        ca_previous_balance = CashAccount.objects.filter(
            account_type=self.from_account
        ).order_by('-id').values('current_balance').first()

        ca_previous_balance = ca_previous_balance['current_balance'] if ca_previous_balance else 0

        # Calculate the current balance
        ca_current_balance = ca_previous_balance + amount_in - amount_out

        # Check if an instance with the same tx_number exists
        existing_cash_account = CashAccount.objects.filter(
            tx_number=f'EP00-{self.id}'
        ).first()

        # Use transaction to handle the update or create logic
        with transaction.atomic():
            if existing_cash_account:
                # Update the existing instance
                existing_cash_account.date = current_date
                existing_cash_account.amount_in = self.amount
                existing_cash_account.previous_balance = ca_previous_balance
                existing_cash_account.current_balance = ca_current_balance
                existing_cash_account.save()
            else:
                # Create a new instance of CashAccount
                cash_account = CashAccount(
                    date=current_date,
                    account_type=self.from_account,
                    tx_number=f'EP00-{self.id}',
                    description=f'Expense Payment #{self.id}',
                    amount_in=0,
                    amount_out=self.amount,
                    previous_balance=ca_previous_balance,
                    current_balance=ca_current_balance,
                    currency=self.currency,
                    remarks=f'Cash account entry for consumer {self.spent_by} payment!'
                )
                cash_account.save()


class ShareHolderWithdrawal(models.Model):
    holder = models.ForeignKey(
        ShareHolders, on_delete=models.PROTECT)
    amount = models.DecimalField(
        max_digits=20, decimal_places=2, default=0, validators=[MinValueValidator(0)])
    currency = models.ForeignKey(Currency, on_delete=models.PROTECT)
    remarks = models.TextField(
        null=True, blank=True, default='null')
    date = models.DateField(default=date.today())
    created_by = models.ForeignKey(
        User, on_delete=models.SET_NULL, related_name='withdraw_created', null=True)
    updated_by = models.ForeignKey(
        User, on_delete=models.SET_NULL, related_name='withdraw_updated', null=True)
    created_at = models.DateTimeField(
        auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f"Holder: {self.holder.name}, Amount: {self.amount}, Date: {self.date}"

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        # Check if a ShareHolderDeposit instance with the same tx_number already exists
        if not ShareHolderDeposit.objects.filter(tx_number=f'HWD0{self.id}').exists():
            deposit_instance = ShareHolderDeposit(
                date=self.date,
                tx_number=f'HWD0{self.id}',
                share_holder=self.holder,
                currency=self.currency,
                amount_in=0,
                amount_out=self.amount,
                remarks=f"Withdrawal: {self.remarks}"
            )
            deposit_instance.save()


class PaymentToDoctor(models.Model):
    CASH_IN_HAND = 'C/H'
    CASH_IN_BANK = 'C/B'
    CASH_ACCOUNTS_CHOICES = [
        (CASH_IN_HAND, 'CASH IN HAND'),
        (CASH_IN_BANK, 'CASH IN BANK')

    ]
    placed_at = models.DateField(blank=True, null=True)
    doctor = models.ForeignKey(Doctor, on_delete=models.PROTECT)
    amount_paid = models.DecimalField(
        max_digits=10, decimal_places=2, default=0)
    from_account = models.CharField(
        max_length=191, choices=CASH_ACCOUNTS_CHOICES, default=CASH_IN_HAND)
    remarks = models.CharField(max_length=191)
    created_by = models.ForeignKey(
        User, on_delete=models.SET_NULL, related_name='payment_to_doctor_created', null=True)
    updated_by = models.ForeignKey(
        User, on_delete=models.SET_NULL, related_name='payment_to_doctor_updated', null=True)
    created_at = models.DateTimeField(
        auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f'{self.doctor}'

    def calculate_doctor_commissions(self):
        debit = self.amount_paid
        credit = 0

        # Retrieve the previous balance for the customer
        previous_balance = DoctorCommission.objects.filter(
            doctor=self.doctor).order_by('-id').values('current_balance').first()
        previous_balance = previous_balance['current_balance'] if previous_balance else 0

        # Calculate the current balance
        current_balance = previous_balance + credit - debit

        # Check if there is an existing DoctorCommission record with the given details
        existing_commission = DoctorCommission.objects.filter(
            doctor=self.doctor, details=f'Commission Paid Voucher #{self.id}'
        ).first()

        if existing_commission:
            # Update the existing DoctorCommission record
            existing_commission.debit = debit
            existing_commission.credit = credit
            existing_commission.current_balance = current_balance
            existing_commission.save()
        else:
            # Create a new DoctorCommission record
            doctor_commission_obj = DoctorCommission(
                doctor=self.doctor,
                details=f'Commission Paid Voucher #{self.id}',
                previous_balance=previous_balance,
                debit=debit,
                credit=credit,
                current_balance=current_balance,
                remarks='No Remarks'
            )
            doctor_commission_obj.save()

    def save(self, *args, **kwargs):

        super().save(*args, **kwargs)
        self.calculate_doctor_commissions()
# --------------------------------------------------------------------------------
#                       Cash Account Related codes
        # Calculate the debit and credit amounts
        amount_in = 0
        amount_out = self.amount_paid
        currency_instance = Currency.objects.first()
        current_date = date.today()

        # Retrieve the previous balance
        ca_previous_balance = CashAccount.objects.filter(
            account_type=self.from_account
        ).order_by('-id').values('current_balance').first()

        ca_previous_balance = ca_previous_balance['current_balance'] if ca_previous_balance else 0

        # Calculate the current balance
        ca_current_balance = ca_previous_balance + amount_in - amount_out

        # Check if an instance with the same tx_number exists
        existing_cash_account = CashAccount.objects.filter(
            tx_number=f'CPTD00-{self.id}'
        ).first()

        # Use transaction to handle the update or create logic
        with transaction.atomic():
            if existing_cash_account:
                # Update the existing instance
                existing_cash_account.date = current_date
                existing_cash_account.amount_in = self.amount_paid
                existing_cash_account.previous_balance = ca_previous_balance
                existing_cash_account.current_balance = ca_current_balance
                existing_cash_account.save()
            else:
                # Create a new instance of CashAccount
                cash_account = CashAccount(
                    date=current_date,
                    account_type=self.from_account,
                    tx_number=f'CPTD00-{self.id}',
                    description=f'Cash Payment to Doctor #{self.doctor}',
                    amount_in=0,
                    amount_out=self.amount_paid,
                    previous_balance=ca_previous_balance,
                    current_balance=ca_current_balance,
                    currency=currency_instance,
                    remarks=f'Cash payment to dr {self.doctor}!'
                )
                cash_account.save()


class AccountPayableReceivable(models.Model):
    ACCOUNT_PAYABLE = 'A/P'
    ACCOUNT_RECEIVABLE = 'A/R'
    ACCOUNT_TYPE_CHOICES = [
        (ACCOUNT_PAYABLE, 'ACCOUNT PAYABLE'),
        (ACCOUNT_RECEIVABLE, 'ACCOUNT RECEIVABLE')

    ]
    date = models.DateField(auto_created=True)
    account_type = models.CharField(
        max_length=3, choices=ACCOUNT_TYPE_CHOICES, default=ACCOUNT_PAYABLE)
    tx_number = models.CharField(max_length=191, unique=True)
    description = models.CharField(max_length=191, default='N/A')
    amount_in = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    amount_out = models.DecimalField(
        max_digits=10, decimal_places=2, default=0)
    currency = models.ForeignKey(Currency, on_delete=models.PROTECT)
    remarks = models.CharField(max_length=191, default='N/A')

    def __str__(self):
        return self.tx_number

    class Meta:
        verbose_name_plural = 'Account Payable & Receivable'


class CashAccount(models.Model):
    CASH_IN_HAND = 'C/H'
    CASH_IN_BANK = 'C/B'
    CASH_ACCOUNTS_CHOICES = [
        (CASH_IN_HAND, 'CASH IN HAND'),
        (CASH_IN_BANK, 'CASH IN BANK')

    ]
    date = models.DateField(blank=True, null=True)
    tx_number = models.CharField(max_length=191, unique=True)
    account_type = models.CharField(
        max_length=3, choices=CASH_ACCOUNTS_CHOICES, default=CASH_IN_HAND)
    description = models.CharField(max_length=191, default='N/A')
    amount_in = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    amount_out = models.DecimalField(
        max_digits=10, decimal_places=2, default=0)
    previous_balance = models.DecimalField(
        max_digits=15, decimal_places=2, default=0)
    current_balance = models.DecimalField(
        max_digits=15, decimal_places=2, default=0)
    currency = models.ForeignKey(Currency, on_delete=models.PROTECT)
    remarks = models.CharField(max_length=191, default='N/A')

    def __str__(self):
        return self.tx_number

    class Meta:
        verbose_name_plural = 'Cash Accounts'

    def save(self, *args, **kwargs):
        # calculate the current balance by adding the previous balance, total credit, and subtracting total debit
        self.current_balance = self.previous_balance + \
            self.amount_in - self.amount_out
        super(CashAccount, self).save(*args, **kwargs)


class ShareHolderDeposit(models.Model):
    date = models.DateField(default=date.today())
    tx_number = models.CharField(max_length=191, default='TX0101')
    share_holder = models.ForeignKey(ShareHolders, on_delete=models.PROTECT)
    currency = models.ForeignKey(Currency, on_delete=models.PROTECT)
    amount_in = models.DecimalField(
        max_digits=12, decimal_places=2, default=0, validators=[MinValueValidator(0)])
    amount_out = models.DecimalField(
        max_digits=12, decimal_places=2, default=0, validators=[MinValueValidator(0)])
    remarks = models.CharField(max_length=191, default='N/A')
    created_by = models.ForeignKey(
        User, on_delete=models.SET_NULL, related_name='deposit_created', null=True)
    updated_by = models.ForeignKey(
        User, on_delete=models.SET_NULL, related_name='deposit_updated', null=True)

    def __str__(self):
        return f'{self.share_holder} - {self.date}'
