from django.conf import settings
from django.db import models
from django.utils import timezone


class Department(models.Model):
    name = models.CharField(max_length=100, unique=True)
    head = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="headed_departments",
    )

    class Meta:
        ordering = ["name"]

    def __str__(self):
        return self.name


class StaffProfile(models.Model):
    class EmploymentType(models.TextChoices):
        PERMANENT = "permanent", "Permanent"
        CONTRACT = "contract", "Contract"
        INTERN = "intern", "Intern"
        CONSULTANT = "consultant", "Consultant"

    class Status(models.TextChoices):
        ACTIVE = "active", "Active"
        ON_LEAVE = "on_leave", "On leave"
        SUSPENDED = "suspended", "Suspended"
        TERMINATED = "terminated", "Terminated"

    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="staff_profile",
    )
    employee_id = models.CharField(max_length=32, unique=True, blank=True)
    department = models.ForeignKey(
        Department,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="staff",
    )
    job_title = models.CharField(max_length=150, blank=True)
    employment_type = models.CharField(
        max_length=16, choices=EmploymentType.choices, default=EmploymentType.PERMANENT
    )
    status = models.CharField(max_length=16, choices=Status.choices, default=Status.ACTIVE)
    date_joined = models.DateField(null=True, blank=True)
    contract_end_date = models.DateField(null=True, blank=True)
    supervisor = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="direct_reports",
    )
    phone = models.CharField(max_length=32, blank=True)
    national_id = models.CharField(max_length=64, blank=True)
    emergency_contact_name = models.CharField(max_length=100, blank=True)
    emergency_contact_phone = models.CharField(max_length=32, blank=True)
    notes = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["user__last_name", "user__first_name"]

    def __str__(self):
        return f"{self.user.get_full_name() or self.user.email} — {self.job_title or 'Staff'}"

    @property
    def annual_leave_entitlement(self) -> int:
        return 21 if self.employment_type == self.EmploymentType.PERMANENT else 14


class LeaveType(models.Model):
    name = models.CharField(max_length=100, unique=True)
    paid = models.BooleanField(default=True)
    max_days_per_year = models.PositiveSmallIntegerField(default=0, help_text="0 = unlimited")
    requires_approval = models.BooleanField(default=True)
    carry_over = models.BooleanField(default=False)

    class Meta:
        ordering = ["name"]

    def __str__(self):
        return self.name


class LeaveBalance(models.Model):
    staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, related_name="leave_balances")
    leave_type = models.ForeignKey(LeaveType, on_delete=models.CASCADE, related_name="balances")
    year = models.PositiveSmallIntegerField()
    entitled_days = models.DecimalField(max_digits=5, decimal_places=1, default=0)
    used_days = models.DecimalField(max_digits=5, decimal_places=1, default=0)
    carried_over = models.DecimalField(max_digits=5, decimal_places=1, default=0)

    class Meta:
        unique_together = [("staff", "leave_type", "year")]
        ordering = ["-year", "leave_type__name"]

    @property
    def remaining(self):
        return self.entitled_days + self.carried_over - self.used_days

    def __str__(self):
        return f"{self.staff} / {self.leave_type} / {self.year}"


class LeaveRequest(models.Model):
    class Status(models.TextChoices):
        PENDING = "pending", "Pending"
        APPROVED = "approved", "Approved"
        REJECTED = "rejected", "Rejected"
        CANCELLED = "cancelled", "Cancelled"

    staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE, 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=5, decimal_places=1)
    reason = models.TextField(blank=True)
    status = models.CharField(max_length=16, choices=Status.choices, default=Status.PENDING)
    reviewed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="leave_reviews",
    )
    reviewed_at = models.DateTimeField(null=True, blank=True)
    review_note = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.staff} — {self.leave_type} ({self.start_date}–{self.end_date})"


class BackToOfficeReport(models.Model):
    staff = models.ForeignKey(
        StaffProfile, on_delete=models.CASCADE, related_name="back_to_office_reports"
    )
    leave_request = models.OneToOneField(
        LeaveRequest,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="back_to_office_report",
    )
    return_date = models.DateField()
    summary = models.TextField(help_text="Brief summary of activities during leave / absence.")
    submitted_at = models.DateTimeField(default=timezone.now)

    class Meta:
        ordering = ["-return_date"]

    def __str__(self):
        return f"BTO: {self.staff} — {self.return_date}"


class TravelRequest(models.Model):
    class Status(models.TextChoices):
        DRAFT = "draft", "Draft"
        PENDING = "pending", "Pending approval"
        APPROVED = "approved", "Approved"
        REJECTED = "rejected", "Rejected"
        COMPLETED = "completed", "Completed"
        CANCELLED = "cancelled", "Cancelled"

    class TravelType(models.TextChoices):
        LOCAL = "local", "Local"
        REGIONAL = "regional", "Regional"
        INTERNATIONAL = "international", "International"

    staff = models.ForeignKey(
        StaffProfile, on_delete=models.CASCADE, related_name="travel_requests"
    )
    purpose = models.CharField(max_length=255)
    destination = models.CharField(max_length=255)
    travel_type = models.CharField(max_length=16, choices=TravelType.choices, default=TravelType.LOCAL)
    departure_date = models.DateField()
    return_date = models.DateField()
    estimated_cost = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    currency = models.CharField(max_length=3, default="USD")
    per_diem_days = models.PositiveSmallIntegerField(default=0)
    status = models.CharField(max_length=16, choices=Status.choices, default=Status.DRAFT)
    approved_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="travel_approvals",
    )
    approved_at = models.DateTimeField(null=True, blank=True)
    notes = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.staff} → {self.destination} ({self.departure_date})"


class TravelReport(models.Model):
    travel_request = models.OneToOneField(
        TravelRequest, on_delete=models.CASCADE, related_name="report"
    )
    summary = models.TextField()
    outcomes = models.TextField(blank=True)
    actual_cost = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    submitted_at = models.DateTimeField(default=timezone.now)

    class Meta:
        ordering = ["-submitted_at"]

    def __str__(self):
        return f"Report: {self.travel_request}"
