from django.conf import settings
from django.db import models
from apps.core.models import TimeStampedModel, ActiveModel
from apps.organization.models import Company
from apps.employees.models import Employee

class SalaryComponent(ActiveModel):
    class Kind(models.TextChoices): EARNING="EARNING","Earning"; DEDUCTION="DEDUCTION","Deduction"
    class CalcType(models.TextChoices): FIXED="FIXED","Fixed"; PERCENTAGE="PERCENTAGE","Percentage"; FORMULA="FORMULA","Formula"
    company = models.ForeignKey(Company, on_delete=models.PROTECT, related_name="salary_components")
    code = models.CharField(max_length=30)
    name = models.CharField(max_length=120)
    kind = models.CharField(max_length=20, choices=Kind.choices)
    calculation_type = models.CharField(max_length=20, choices=CalcType.choices, default=CalcType.FIXED)
    taxable = models.BooleanField(default=False)
    recurring = models.BooleanField(default=True)
    class Meta:
        constraints = [models.UniqueConstraint(fields=["company", "code"], name="uq_salary_component_company_code")]
    def __str__(self): return f"{self.code} - {self.name}"

class SalaryStructure(ActiveModel):
    company = models.ForeignKey(Company, on_delete=models.PROTECT, related_name="salary_structures")
    name = models.CharField(max_length=120)
    code = models.CharField(max_length=30)
    class Meta:
        constraints = [models.UniqueConstraint(fields=["company", "code"], name="uq_salary_structure_company_code")]
    def __str__(self): return f"{self.code} - {self.name}"

class SalaryStructureLine(TimeStampedModel):
    structure = models.ForeignKey(SalaryStructure, on_delete=models.CASCADE, related_name="lines")
    component = models.ForeignKey(SalaryComponent, on_delete=models.PROTECT, related_name="structure_lines")
    amount = models.DecimalField(max_digits=14, decimal_places=2, default=0)
    percentage = models.DecimalField(max_digits=8, decimal_places=4, default=0)
    formula = models.CharField(max_length=255, blank=True)
    class Meta:
        constraints = [models.UniqueConstraint(fields=["structure", "component"], name="uq_structure_component")]

class EmployeeSalaryAssignment(TimeStampedModel):
    employee = models.ForeignKey(Employee, on_delete=models.PROTECT, related_name="salary_assignments")
    structure = models.ForeignKey(SalaryStructure, on_delete=models.PROTECT, related_name="employee_assignments")
    effective_from = models.DateField()
    effective_to = models.DateField(null=True, blank=True)
    gross_salary = models.DecimalField(max_digits=14, decimal_places=2)
    basic_salary = models.DecimalField(max_digits=14, decimal_places=2)
    ot_eligible = models.BooleanField(default=False)
    ot_rate_multiplier = models.DecimalField(max_digits=6, decimal_places=2, default=1.00)
    notes = models.TextField(blank=True)
    class Meta:
        indexes = [models.Index(fields=["employee", "effective_from"])]

class Bonus(TimeStampedModel):
    employee = models.ForeignKey(Employee, on_delete=models.PROTECT, related_name="bonuses")
    payroll_month = models.DateField(help_text="Canonical payroll month; stored as the first day of the month.")
    bonus_type = models.CharField(max_length=80)
    amount = models.DecimalField(max_digits=14, decimal_places=2)
    status = models.CharField(max_length=20, default="PENDING")
    reason = models.TextField(blank=True)

    def save(self, *args, **kwargs):
        if self.payroll_month:
            self.payroll_month = self.payroll_month.replace(day=1)
        return super().save(*args, **kwargs)

class Deduction(TimeStampedModel):
    employee = models.ForeignKey(Employee, on_delete=models.PROTECT, related_name="deductions")
    payroll_month = models.DateField(help_text="Canonical payroll month; stored as the first day of the month.")
    deduction_type = models.CharField(max_length=80)
    amount = models.DecimalField(max_digits=14, decimal_places=2)
    status = models.CharField(max_length=20, default="PENDING")
    reason = models.TextField(blank=True)

    def save(self, *args, **kwargs):
        if self.payroll_month:
            self.payroll_month = self.payroll_month.replace(day=1)
        return super().save(*args, **kwargs)

class PayrollPeriod(TimeStampedModel):
    class Status(models.TextChoices): DRAFT="DRAFT","Draft"; REVIEWED="REVIEWED","Reviewed"; APPROVED="APPROVED","Approved"; LOCKED="LOCKED","Locked"
    class PaymentStatus(models.TextChoices): UNPAID="UNPAID","Unpaid"; PAID="PAID","Paid"
    company = models.ForeignKey(Company, on_delete=models.PROTECT, related_name="payroll_periods")
    year = models.PositiveIntegerField()
    month = models.PositiveIntegerField()
    status = models.CharField(max_length=20, choices=Status.choices, default=Status.DRAFT)
    locked_at = models.DateTimeField(null=True, blank=True)
    unlock_reason = models.TextField(blank=True)
    payment_status = models.CharField(max_length=20, choices=PaymentStatus.choices, default=PaymentStatus.UNPAID)
    paid_at = models.DateTimeField(null=True, blank=True)
    payment_reference = models.CharField(max_length=160, blank=True)
    prepared_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True, related_name="prepared_payroll_periods")
    reviewed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True, related_name="reviewed_payroll_periods")
    approved_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True, related_name="approved_payroll_periods")
    locked_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True, related_name="locked_payroll_periods")
    paid_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True, related_name="paid_payroll_periods")
    class Meta:
        constraints = [models.UniqueConstraint(fields=["company", "year", "month"], name="uq_payroll_company_month")]

class PayrollRecord(TimeStampedModel):
    period = models.ForeignKey(PayrollPeriod, on_delete=models.PROTECT, related_name="records")
    employee = models.ForeignKey(Employee, on_delete=models.PROTECT, related_name="payroll_records")
    salary_assignment = models.ForeignKey(EmployeeSalaryAssignment, on_delete=models.PROTECT, related_name="payroll_records")
    gross_salary = models.DecimalField(max_digits=14, decimal_places=2, default=0)
    basic_salary = models.DecimalField(max_digits=14, decimal_places=2, default=0)
    attendance_deduction = models.DecimalField(max_digits=14, decimal_places=2, default=0)
    overtime_amount = models.DecimalField(max_digits=14, decimal_places=2, default=0)
    bonus_amount = models.DecimalField(max_digits=14, decimal_places=2, default=0)
    other_earnings = models.DecimalField(max_digits=14, decimal_places=2, default=0)
    deduction_amount = models.DecimalField(max_digits=14, decimal_places=2, default=0)
    loan_recovery = models.DecimalField(max_digits=14, decimal_places=2, default=0)
    net_payable = models.DecimalField(max_digits=14, decimal_places=2, default=0)
    calculation_snapshot = models.JSONField(default=dict, blank=True)
    class Meta:
        constraints = [models.UniqueConstraint(fields=["period", "employee"], name="uq_payroll_period_employee")]

class PayrollLineItem(TimeStampedModel):
    payroll = models.ForeignKey(PayrollRecord, on_delete=models.CASCADE, related_name="line_items")
    component_code = models.CharField(max_length=50)
    component_name = models.CharField(max_length=120)
    kind = models.CharField(max_length=20)
    amount = models.DecimalField(max_digits=14, decimal_places=2)
    source = models.CharField(max_length=60, blank=True)

class PayrollAdjustment(TimeStampedModel):
    payroll = models.ForeignKey(PayrollRecord, on_delete=models.PROTECT, related_name="adjustments")
    adjustment_type = models.CharField(max_length=30)
    amount = models.DecimalField(max_digits=14, decimal_places=2)
    reason = models.TextField()
    reference_no = models.CharField(max_length=60, blank=True)
