from django.core.exceptions import ValidationError
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 LeaveType(ActiveModel):
    company = models.ForeignKey(Company, on_delete=models.PROTECT, related_name="leave_types")
    code = models.CharField(max_length=30)
    name = models.CharField(max_length=100)
    yearly_allocation = models.DecimalField(max_digits=6, decimal_places=2, default=0)
    is_paid = models.BooleanField(default=True)
    carry_forward = models.BooleanField(default=False)
    max_carry_forward = models.DecimalField(max_digits=6, decimal_places=2, default=0)
    half_day_allowed = models.BooleanField(default=True)
    class Meta:
        constraints = [models.UniqueConstraint(fields=["company", "code"], name="uq_leave_type_company_code")]
    def __str__(self): return f"{self.code} - {self.name}"

class LeaveBalance(TimeStampedModel):
    employee = models.ForeignKey(Employee, on_delete=models.PROTECT, related_name="leave_balances")
    leave_type = models.ForeignKey(LeaveType, on_delete=models.PROTECT, related_name="balances")
    year = models.PositiveIntegerField()
    opening = models.DecimalField(max_digits=7, decimal_places=2, default=0)
    allocated = models.DecimalField(max_digits=7, decimal_places=2, default=0)
    used = models.DecimalField(max_digits=7, decimal_places=2, default=0)
    adjusted = models.DecimalField(max_digits=7, decimal_places=2, default=0)
    class Meta:
        constraints = [models.UniqueConstraint(fields=["employee", "leave_type", "year"], name="uq_leave_balance_year")]
    @property
    def available(self): return self.opening + self.allocated + self.adjusted - self.used

    def clean(self):
        super().clean()
        if self.employee_id and self.leave_type_id and self.employee.company_id != self.leave_type.company_id:
            raise ValidationError({"leave_type": "Leave type must belong to the employee's company."})
        for field_name in ("opening", "allocated", "used"):
            value = getattr(self, field_name, 0)
            if value is not None and value < 0:
                raise ValidationError({field_name: f"{field_name.replace('_', ' ').title()} cannot be negative."})

class LeaveRequest(TimeStampedModel):
    employee = models.ForeignKey(Employee, on_delete=models.PROTECT, related_name="leave_requests")
    leave_type = models.ForeignKey(LeaveType, on_delete=models.PROTECT, related_name="requests")
    start_date = models.DateField()
    end_date = models.DateField()
    days = models.DecimalField(max_digits=6, decimal_places=2)
    reason = models.TextField(blank=True)
    status = models.CharField(max_length=20, default="PENDING")
    reviewer_note = models.TextField(blank=True)
    rejection_reason = models.TextField(blank=True)

    def clean(self):
        super().clean()
        if self.employee_id and self.leave_type_id and self.employee.company_id != self.leave_type.company_id:
            raise ValidationError({"leave_type": "Leave type must belong to the employee's company."})
        if self.start_date and self.end_date and self.end_date < self.start_date:
            raise ValidationError({"end_date": "End date cannot be earlier than start date."})
        if self.days is not None and self.days <= 0:
            raise ValidationError({"days": "Leave days must be greater than zero."})
