import os
from io import BytesIO
from PIL import Image
from decimal import Decimal
from django.db import models
from django.conf import settings
from django.core.files.base import ContentFile
from django.utils import timezone
# Reuse your existing helpers/choices if they are already centrally available.
# Update these imports according to your actual project structure.
from django.core.exceptions import ValidationError
#from django.core.files.base import ContentFile
from common.choices import SRI_LANKA_CITY_CHOICES, SRI_LANKA_DISTRICT_CHOICES


def validate_image_file(image):
    allowed_extensions = ['.jpg', '.jpeg', '.png', '.webp']
    ext = os.path.splitext(image.name)[1].lower()

    if ext not in allowed_extensions:
        raise ValidationError("Only JPG, JPEG, PNG, and WEBP images are allowed.")

    max_size_mb = 5
    if image.size > max_size_mb * 1024 * 1024:
        raise ValidationError(f"Image file too large. Maximum allowed size is {max_size_mb} MB.")
    
def validate_property_document_file(file):
    """
    Validates uploaded managed property supporting documents.
    Allows PDFs and common image formats.
    """

    allowed_extensions = ['.pdf', '.jpg', '.jpeg', '.png', '.webp']
    extension = os.path.splitext(file.name)[1].lower()

    if extension not in allowed_extensions:
        raise ValidationError(
            "Unsupported file type. Please upload PDF, JPG, JPEG, PNG, or WEBP files only."
        )

    max_file_size_mb = 10
    if file.size > max_file_size_mb * 1024 * 1024:
        raise ValidationError(
            f"File size must not exceed {max_file_size_mb} MB."
        )
    
class PropertyManagerClientProfile(models.Model):
    CLIENT_TYPE_CHOICES = [
        ('individual', 'Individual'),
        ('family', 'Family Representative'),
        ('company', 'Company'),
        ('estate_owner', 'Estate Owner'),
        ('other', 'Other'),
    ]

    RESIDENCY_STATUS_CHOICES = [
        ('overseas', 'Living Overseas'),
        ('in_sri_lanka_away', 'Living in Sri Lanka but Away from Property'),
        ('frequent_traveller', 'Frequently Travelling'),
        ('other', 'Other'),
    ]

    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='property_manager_client_profile'
    )

    client_type = models.CharField(
        max_length=30,
        choices=CLIENT_TYPE_CHOICES,
        default='individual'
    )

    residency_status = models.CharField(
        max_length=40,
        choices=RESIDENCY_STATUS_CHOICES,
        default='overseas'
    )

    full_name = models.CharField(max_length=150)
    email = models.EmailField()
    whatsapp_number = models.CharField(max_length=50, blank=True)
    phone_number = models.CharField(max_length=50, blank=True)

    current_country = models.CharField(max_length=120, blank=True)
    current_city = models.CharField(max_length=120, blank=True)

    emergency_contact_name = models.CharField(max_length=150, blank=True)
    emergency_contact_phone = models.CharField(max_length=50, blank=True)

    profile_image = models.ImageField(
        upload_to='property_manager/client_profiles/',
        blank=True,
        null=True,
        validators=[validate_image_file]
    )

    short_note = models.TextField(
        blank=True,
        help_text="Optional note about the owner's situation or property care expectations."
    )

    is_identity_verified = models.BooleanField(default=False)
    is_approved = models.BooleanField(default=True)
    can_submit_properties = models.BooleanField(default=True)

    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name = 'Property Manager Client Profile'
        verbose_name_plural = 'Property Manager Client Profiles'

    def __str__(self):
        return self.full_name

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        if self.profile_image:
            self.compress_profile_image()

    def compress_profile_image(self):
        try:
            img = Image.open(self.profile_image.path)

            if img.mode in ('RGBA', 'P'):
                img = img.convert('RGB')

            max_width = 800
            max_height = 800
            img.thumbnail((max_width, max_height))

            buffer = BytesIO()
            img.save(buffer, format='JPEG', quality=85, optimize=True)

            file_name = os.path.splitext(
                os.path.basename(self.profile_image.name)
            )[0] + '.jpg'

            self.profile_image.save(
                file_name,
                ContentFile(buffer.getvalue()),
                save=False
            )

            super().save(update_fields=['profile_image'])

        except Exception:
            pass

class ManagedProperty(models.Model):
    PROPERTY_CATEGORY_CHOICES = [
        ('vacant_land', 'Vacant Land'),
        ('land_with_house', 'Land with House'),
        ('house', 'House'),
        ('villa', 'Villa'),
        ('apartment', 'Apartment'),
        ('commercial_building', 'Commercial Building'),
        ('estate', 'Estate / Plantation Property'),
        ('mixed_property', 'Mixed Property'),
        ('other', 'Other'),
    ]

    PROPERTY_OCCUPANCY_CHOICES = [
        ('vacant', 'Vacant'),
        ('occupied_by_family', 'Occupied by Family'),
        ('rented', 'Currently Rented'),
        ('under_construction', 'Under Construction'),
        ('occasionally_used', 'Occasionally Used'),
        ('other', 'Other'),
    ]

    LAND_UNIT_CHOICES = [
        ('perches', 'Perches'),
        ('acres', 'Acres'),
    ]

    FLOOR_AREA_UNIT_CHOICES = [
        ('sqft', 'Square Feet'),
        ('sqm', 'Square Meters'),
    ]

    PROPERTY_AGE_CHOICES = [
        ('under_5', 'Under 5 Years'),
        ('5_to_15', '5 – 15 Years'),
        ('15_to_30', '15 – 30 Years'),
        ('over_30', 'Over 30 Years'),
        ('unknown', 'Unknown'),
    ]

    PROPERTY_CONDITION_CHOICES = [
        ('excellent', 'Excellent'),
        ('good', 'Good'),
        ('fair', 'Fair'),
        ('needs_attention', 'Needs Attention'),
        ('poor', 'Poor / Neglected'),
    ]

    REVIEW_STATUS_CHOICES = [
        ('draft', 'Draft'),
        ('submitted', 'Submitted for Review'),
        ('approved', 'Approved'),
        ('rejected', 'Rejected'),
    ]

    owner = models.ForeignKey(
        PropertyManagerClientProfile,
        on_delete=models.CASCADE,
        related_name='managed_properties'
    )

    property_name = models.CharField(
        max_length=200,
        help_text="A friendly name to identify this property."
    )

    property_category = models.CharField(
        max_length=40,
        choices=PROPERTY_CATEGORY_CHOICES
    )

    occupancy_status = models.CharField(
        max_length=40,
        choices=PROPERTY_OCCUPANCY_CHOICES,
        default='vacant'
    )

    city = models.CharField(
        max_length=120,
        choices=SRI_LANKA_CITY_CHOICES,
        blank=True
    )

    district = models.CharField(
        max_length=120,
        choices=SRI_LANKA_DISTRICT_CHOICES,
        blank=True
    )

    address = models.TextField(blank=True)

    google_map_link = models.URLField(blank=True)

    # Land details
    land_size = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        null=True,
        blank=True
    )

    land_size_unit = models.CharField(
        max_length=20,
        choices=LAND_UNIT_CHOICES,
        default='perches'
    )

    # Building details
    number_of_buildings = models.PositiveIntegerField(default=0)

    total_floor_area = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        null=True,
        blank=True
    )

    floor_area_unit = models.CharField(
        max_length=20,
        choices=FLOOR_AREA_UNIT_CHOICES,
        default='sqft'
    )

    number_of_storeys = models.PositiveIntegerField(default=0)
    bedrooms = models.PositiveIntegerField(default=0)
    bathrooms = models.PositiveIntegerField(default=0)
    kitchens = models.PositiveIntegerField(default=0)
    living_rooms = models.PositiveIntegerField(default=0)
    other_rooms = models.PositiveIntegerField(default=0)

    property_age = models.CharField(
        max_length=30,
        choices=PROPERTY_AGE_CHOICES,
        default='unknown'
    )

    current_condition = models.CharField(
        max_length=30,
        choices=PROPERTY_CONDITION_CHOICES,
        default='good'
    )

    # Property access and maintenance relevance
    has_boundary_wall_or_fence = models.BooleanField(default=False)
    has_gate = models.BooleanField(default=False)
    has_garden_or_landscape = models.BooleanField(default=False)
    needs_grass_cutting = models.BooleanField(default=False)

    electricity_active = models.BooleanField(default=False)
    water_active = models.BooleanField(default=False)
    internet_active = models.BooleanField(default=False)

    needs_key_holding_service = models.BooleanField(default=False)
    allows_emergency_access = models.BooleanField(default=False)

    owner_notes = models.TextField(
        blank=True,
        help_text="Any important note from the owner about the property or expected care."
    )

    # Internal/admin control

    review_status = models.CharField(
        max_length=20,
        choices=REVIEW_STATUS_CHOICES,
        default='draft'
    )

    submitted_for_review_at = models.DateTimeField(
        null=True,
        blank=True
    )

    reviewed_at = models.DateTimeField(
        null=True,
        blank=True
    )

    reviewed_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='reviewed_managed_properties'
    )

    staff_review_note = models.TextField(
        blank=True,
        help_text="Internal review note or rejection reason recorded by staff."
    )

    is_submitted_for_review = models.BooleanField(default=False)
    is_approved = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)

    selected_services = models.ManyToManyField(
        'MaintenanceServiceType',
        through='PropertyServiceSelection',
        related_name='selected_for_properties',
        blank=True
    )

    estimated_monthly_total_usd = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        null=True,
        blank=True,
        help_text="Latest calculator-generated provisional monthly maintenance estimate."
    )

    estimate_generated_at = models.DateTimeField(
        null=True,
        blank=True
    )

    has_custom_quote_services = models.BooleanField(
        default=False,
        help_text="True when one or more selected services require staff quotation or cannot be auto-calculated."
    )

    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name = 'Managed Property'
        verbose_name_plural = 'Managed Properties'

    def __str__(self):
        return f"{self.property_name} - {self.owner.full_name}"
    
class ManagedPropertyImage(models.Model):
    property = models.ForeignKey(
        ManagedProperty,
        on_delete=models.CASCADE,
        related_name='images'
    )

    image = models.ImageField(
        upload_to='property_manager/property_images/',
        validators=[validate_image_file]
    )

    caption = models.CharField(max_length=150, blank=True)
    order = models.PositiveIntegerField(default=0)

    class Meta:
        ordering = ['order', 'id']
        verbose_name = 'Managed Property Image'
        verbose_name_plural = 'Managed Property Images'

    def __str__(self):
        return f"{self.property.property_name} Image"

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        if self.image:
            self.compress_image()

    def compress_image(self):
        try:
            img = Image.open(self.image.path)

            if img.mode in ('RGBA', 'P'):
                img = img.convert('RGB')

            max_width = 1600
            max_height = 1600
            img.thumbnail((max_width, max_height))

            buffer = BytesIO()
            img.save(buffer, format='JPEG', quality=85, optimize=True)

            file_name = os.path.splitext(
                os.path.basename(self.image.name)
            )[0] + '.jpg'

            self.image.save(
                file_name,
                ContentFile(buffer.getvalue()),
                save=False
            )

            super().save(update_fields=['image'])

        except Exception:
            pass

class ManagedPropertyDocument(models.Model):
    """
    Supporting documents uploaded for a managed property.

    Examples:
    - Land survey plan
    - Building plan / floor plan
    - Ownership proof
    - Utility reference document
    - Other relevant supporting files
    """

    DOCUMENT_TYPE_CHOICES = [
        ('land_plan', 'Land Plan / Survey Plan'),
        ('building_plan', 'Building Plan / Floor Plan'),
        ('ownership_proof', 'Ownership Proof / Deed Reference'),
        ('utility_document', 'Utility Bill / Utility Reference'),
        ('condition_reference', 'Property Condition Reference'),
        ('repair_reference', 'Repair / Maintenance Reference'),
        ('other', 'Other Supporting Document'),
    ]

    property = models.ForeignKey(
        ManagedProperty,
        on_delete=models.CASCADE,
        related_name='documents'
    )

    document_type = models.CharField(
        max_length=40,
        choices=DOCUMENT_TYPE_CHOICES,
        default='other'
    )

    title = models.CharField(
        max_length=255,
        help_text="Short title to identify this document."
    )

    file = models.FileField(
        upload_to='property_care/property_documents/',
        validators=[validate_property_document_file]
    )

    description = models.TextField(
        blank=True,
        help_text="Optional explanation about this document and why it is relevant."
    )

    is_owner_visible = models.BooleanField(
        default=True,
        help_text="If enabled, this document may appear in owner-facing property records later."
    )

    is_staff_verified = models.BooleanField(
        default=False,
        help_text="Enable after staff checks that this document is appropriate and readable."
    )

    uploaded_by_owner = models.BooleanField(
        default=True,
        help_text="True when uploaded by the property owner; false if uploaded by staff."
    )

    uploaded_by_staff = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='managed_property_documents_uploaded'
    )

    uploaded_at = models.DateTimeField(
        auto_now_add=True
    )

    class Meta:
        ordering = ['-uploaded_at']
        verbose_name = 'Managed Property Document'
        verbose_name_plural = 'Managed Property Documents'

    def __str__(self):
        return f"{self.get_document_type_display()} - {self.property.property_name}"


class MaintenanceServiceType(models.Model):
    """
    Master catalogue of maintenance / property care services
    that owners can choose for a managed property.
    """

    SERVICE_CATEGORY_CHOICES = [
        ('inspection', 'Inspection & Reporting'),
        ('cleaning', 'Cleaning & Housekeeping'),
        ('garden', 'Garden & Outdoor Care'),
        ('land_care', 'Vacant Land Care'),
        ('utilities', 'Utilities & Bill Handling'),
        ('security', 'Security & Vacancy Monitoring'),
        ('emergency', 'Emergency Response Support'),
        ('arrival_preparation', 'Arrival / Property Readiness'),
        ('repair_coordination', 'Repair & Maintenance Coordination'),
        ('management', 'General Remote Property Management'),
        ('other', 'Other'),
    ]

    CALCULATION_METHOD_CHOICES = [
        ('flat_monthly', 'Flat Monthly Fee'),
        ('per_visit', 'Per Visit'),
        ('per_land_unit', 'Based on Land Size'),
        ('per_floor_area', 'Based on Floor Area'),
        ('per_building', 'Based on Number of Buildings'),
        ('per_room', 'Based on Room Count'),
        ('custom_quote', 'Custom Quote Required'),
    ]

    code = models.SlugField(
        max_length=120,
        unique=True,
        help_text="Internal unique code, e.g. inspection-visits, garden-care."
    )

    name = models.CharField(
        max_length=180
    )

    category = models.CharField(
        max_length=40,
        choices=SERVICE_CATEGORY_CHOICES
    )

    short_description = models.CharField(
        max_length=255,
        blank=True
    )

    description = models.TextField(
        blank=True
    )

    icon_class = models.CharField(
        max_length=120,
        blank=True,
        help_text="Optional Bootstrap icon class, e.g. bi bi-binoculars-fill."
    )

    # Future calculator support
    calculation_method = models.CharField(
        max_length=40,
        choices=CALCULATION_METHOD_CHOICES,
        default='custom_quote'
    )

    base_monthly_price_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=Decimal('0.00'),
        help_text="Optional starting monthly fee for calculator use."
    )

    price_per_unit_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=Decimal('0.00'),
        help_text="Optional unit price used later by the calculator."
    )

    pricing_unit_label = models.CharField(
        max_length=120,
        blank=True,
        help_text="Example: per visit, per perch, per 100 sq.ft, per building."
    )

    minimum_monthly_price_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        default=Decimal('0.00')
    )

    is_calculator_enabled = models.BooleanField(
        default=False,
        help_text="If enabled, this service can later contribute to the automated monthly estimate."
    )

    requires_staff_quote = models.BooleanField(
        default=False,
        help_text="If true, the service should be shown as requiring review/custom quotation."
    )

    is_active = models.BooleanField(
        default=True
    )

    display_order = models.PositiveIntegerField(
        default=0
    )

    created_at = models.DateTimeField(
        auto_now_add=True
    )

    updated_at = models.DateTimeField(
        auto_now=True
    )

    class Meta:
        ordering = ['display_order', 'category', 'name']
        verbose_name = 'Maintenance Service Type'
        verbose_name_plural = 'Maintenance Service Types'

    def __str__(self):
        return self.name
    
class PropertyServiceSelection(models.Model):
    """
    Stores a service type selected by the property owner
    for a specific managed property.
    """

    FREQUENCY_CHOICES = [
        ('one_time', 'One-Time / As Needed'),
        ('monthly_once', 'Once per Month'),
        ('monthly_twice', 'Twice per Month'),
        ('weekly_once', 'Once per Week'),
        ('weekly_twice', 'Twice per Week'),
        ('custom', 'Custom Frequency'),
    ]

    SELECTION_STATUS_CHOICES = [
        ('draft', 'Draft'),
        ('requested', 'Requested by Owner'),
        ('under_review', 'Under Review'),
        ('approved', 'Approved for Plan'),
        ('not_included', 'Not Included'),
    ]

    property = models.ForeignKey(
        ManagedProperty,
        on_delete=models.CASCADE,
        related_name='service_selections'
    )

    service_type = models.ForeignKey(
        MaintenanceServiceType,
        on_delete=models.PROTECT,
        related_name='property_selections'
    )

    frequency = models.CharField(
        max_length=30,
        choices=FREQUENCY_CHOICES,
        default='monthly_once'
    )

    custom_frequency_note = models.CharField(
        max_length=255,
        blank=True,
        help_text="Used when frequency is custom."
    )

    requested_visits_per_month = models.PositiveIntegerField(
        default=1,
        help_text="Optional clearer operational count for future estimation."
    )

    owner_note = models.TextField(
        blank=True,
        help_text="Owner-specific note or expectation for this service."
    )

    # Future estimate/calculator hooks
    estimated_monthly_amount_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True
    )

    final_monthly_amount_usd = models.DecimalField(
        max_digits=10,
        decimal_places=2,
        null=True,
        blank=True
    )

    selection_status = models.CharField(
        max_length=30,
        choices=SELECTION_STATUS_CHOICES,
        default='requested'
    )

    staff_note = models.TextField(
        blank=True,
        help_text="Internal staff review note for this selected service."
    )

    created_at = models.DateTimeField(
        auto_now_add=True
    )

    updated_at = models.DateTimeField(
        auto_now=True
    )

    class Meta:
        ordering = ['service_type__display_order', 'service_type__name']
        verbose_name = 'Property Service Selection'
        verbose_name_plural = 'Property Service Selections'
        constraints = [
            models.UniqueConstraint(
                fields=['property', 'service_type'],
                name='unique_service_selection_per_property'
            )
        ]

    def __str__(self):
        return f"{self.property.property_name} - {self.service_type.name}"
    
class PropertyCarePlan(models.Model):
    """
    Staff-prepared final property care plan for an approved managed property.
    This converts:
    owner request + calculator estimate
    into:
    Ensolanka's final operational care plan.
    """

    PLAN_STATUS_CHOICES = [
        ('draft', 'Draft'),
        ('finalized', 'Finalized'),
        ('superseded', 'Superseded'),
    ]

    property = models.OneToOneField(
        ManagedProperty,
        on_delete=models.CASCADE,
        related_name='care_plan'
    )

    plan_status = models.CharField(
        max_length=30,
        choices=PLAN_STATUS_CHOICES,
        default='draft'
    )

    provisional_estimate_snapshot_usd = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        null=True,
        blank=True,
        help_text="Snapshot of the calculator estimate available when the care plan was prepared."
    )

    final_monthly_fee_usd = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        null=True,
        blank=True,
        help_text="Final approved recurring monthly care fee calculated from included plan service lines."
    )

    start_date = models.DateField(
        null=True,
        blank=True,
        help_text="Approved service start date."
    )

    general_exclusions = models.TextField(
        blank=True,
        help_text="General exclusions that apply to the finalized care plan."
    )

    plan_notes = models.TextField(
        blank=True,
        help_text="Final plan notes, internal operational guidance, or owner-facing plan remarks."
    )

    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='created_property_care_plans'
    )

    updated_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='updated_property_care_plans'
    )

    finalized_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='finalized_property_care_plans'
    )

    finalized_at = models.DateTimeField(
        null=True,
        blank=True
    )

    created_at = models.DateTimeField(
        auto_now_add=True
    )

    updated_at = models.DateTimeField(
        auto_now=True
    )

    class Meta:
        ordering = ['-created_at']
        verbose_name = 'Property Care Plan'
        verbose_name_plural = 'Property Care Plans'

    def __str__(self):
        return f"Care Plan - {self.property.property_name}"

    def is_finalized(self):
        return self.plan_status == 'finalized'
    
class PropertyCarePlanServiceLine(models.Model):
    """
    Final staff-approved or excluded service line
    belonging to a PropertyCarePlan.
    """

    plan = models.ForeignKey(
        PropertyCarePlan,
        on_delete=models.CASCADE,
        related_name='service_lines'
    )

    source_selection = models.ForeignKey(
        PropertyServiceSelection,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='care_plan_lines'
    )

    service_type = models.ForeignKey(
        MaintenanceServiceType,
        on_delete=models.PROTECT,
        related_name='care_plan_service_lines'
    )

    is_included = models.BooleanField(
        default=True
    )

    final_frequency = models.CharField(
        max_length=30,
        choices=PropertyServiceSelection.FREQUENCY_CHOICES,
        default='monthly_once'
    )

    final_visits_per_month = models.PositiveIntegerField(
        default=1
    )

    final_monthly_amount_usd = models.DecimalField(
        max_digits=12,
        decimal_places=2,
        default=0
    )

    line_note = models.TextField(
        blank=True,
        help_text="Staff note explaining how this service is included or handled."
    )

    exclusion_reason = models.TextField(
        blank=True,
        help_text="Reason this owner-requested service was excluded, if not included."
    )

    display_order = models.PositiveIntegerField(
        default=0
    )

    created_at = models.DateTimeField(
        auto_now_add=True
    )

    updated_at = models.DateTimeField(
        auto_now=True
    )

    class Meta:
        ordering = ['display_order', 'service_type__name']
        verbose_name = 'Property Care Plan Service Line'
        verbose_name_plural = 'Property Care Plan Service Lines'
        constraints = [
            models.UniqueConstraint(
                fields=['plan', 'service_type'],
                name='unique_service_type_per_property_care_plan'
            )
        ]

    def __str__(self):
        return f"{self.plan.property.property_name} - {self.service_type.name}"
    
class PropertyMaintenanceVisit(models.Model):
    """
    Represents a scheduled or completed operational visit
    made by the Ensolanka Property Care team for a managed property.
    """

    VISIT_TYPE_CHOICES = [
        ('inspection', 'Inspection Visit'),
        ('cleaning', 'Cleaning Visit'),
        ('garden_care', 'Garden / Outdoor Care Visit'),
        ('security_check', 'Security Check'),
        ('utility_handling', 'Utility Handling Visit'),
        ('arrival_preparation', 'Arrival Preparation Visit'),
        ('emergency_response', 'Emergency Response Visit'),
        ('repair_followup', 'Repair Follow-up Visit'),
        ('general_visit', 'General Property Care Visit'),
    ]

    VISIT_STATUS_CHOICES = [
        ('scheduled', 'Scheduled'),
        ('in_progress', 'In Progress'),
        ('completed', 'Completed'),
        ('cancelled', 'Cancelled'),
        ('rescheduled', 'Rescheduled'),
    ]

    managed_property = models.ForeignKey(
        ManagedProperty,
        on_delete=models.CASCADE,
        related_name='maintenance_visits'
    )

    care_plan = models.ForeignKey(
        PropertyCarePlan,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='maintenance_visits',
        help_text="Optional: linked finalized care plan under which this visit is performed."
    )

    related_service_type = models.ForeignKey(
        MaintenanceServiceType,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='maintenance_visits',
        help_text="Optional: selected/final care service that this visit mainly relates to."
    )

    visit_title = models.CharField(
        max_length=255,
        help_text="Example: Monthly Inspection Visit - June 2026."
    )

    visit_type = models.CharField(
        max_length=40,
        choices=VISIT_TYPE_CHOICES,
        default='general_visit'
    )

    visit_status = models.CharField(
        max_length=30,
        choices=VISIT_STATUS_CHOICES,
        default='scheduled'
    )

    scheduled_date = models.DateField(
        null=True,
        blank=True
    )

    scheduled_time = models.TimeField(
        null=True,
        blank=True
    )

    completed_at = models.DateTimeField(
        null=True,
        blank=True
    )

    visited_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='property_care_visits_completed',
        help_text="Staff user primarily responsible for this visit."
    )

    visit_summary = models.TextField(
        blank=True,
        help_text="General summary of what was done during the visit."
    )

    owner_visible_note = models.TextField(
        blank=True,
        help_text="Note that may be shown to the property owner."
    )

    internal_note = models.TextField(
        blank=True,
        help_text="Internal staff-only operational note."
    )

    is_owner_visible = models.BooleanField(
        default=False,
        help_text="If enabled, this visit can later appear in the owner report center."
    )

    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='property_care_visits_created'
    )

    created_at = models.DateTimeField(
        auto_now_add=True
    )

    updated_at = models.DateTimeField(
        auto_now=True
    )

    class Meta:
        ordering = ['-scheduled_date', '-created_at']
        verbose_name = 'Property Maintenance Visit'
        verbose_name_plural = 'Property Maintenance Visits'

    def __str__(self):
        return f"{self.visit_title} - {self.managed_property.property_name}"


class PropertyVisitPhoto(models.Model):
    """
    Stores photos uploaded for a property maintenance visit.
    These may be owner-visible evidence photos, issue photos,
    or before/after records.
    """

    PHOTO_TYPE_CHOICES = [
        ('before', 'Before Visit'),
        ('after', 'After Visit'),
        ('issue', 'Issue / Concern'),
        ('general', 'General Property View'),
        ('completion_proof', 'Completion Proof'),
        ('other', 'Other'),
    ]

    visit = models.ForeignKey(
        PropertyMaintenanceVisit,
        on_delete=models.CASCADE,
        related_name='photos'
    )

    image = models.ImageField(
        upload_to='property_care/visit_photos/',
        validators=[validate_image_file]
    )

    photo_type = models.CharField(
        max_length=30,
        choices=PHOTO_TYPE_CHOICES,
        default='general'
    )

    caption = models.CharField(
        max_length=255,
        blank=True
    )

    is_owner_visible = models.BooleanField(
        default=True,
        help_text="If enabled, this image can appear in the owner's service tracking view."
    )

    uploaded_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='property_visit_photos_uploaded'
    )

    uploaded_at = models.DateTimeField(
        auto_now_add=True
    )

    class Meta:
        ordering = ['-uploaded_at']
        verbose_name = 'Property Visit Photo'
        verbose_name_plural = 'Property Visit Photos'

    def __str__(self):
        return f"Visit Photo - {self.visit.visit_title}"

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        if self.image:
            self.compress_image()

    def compress_image(self):
        try:
            img = Image.open(self.image.path)

            if img.mode in ('RGBA', 'P'):
                img = img.convert('RGB')

            max_width = 1600
            max_height = 1600
            img.thumbnail((max_width, max_height))

            buffer = BytesIO()
            img.save(
                buffer,
                format='JPEG',
                quality=85,
                optimize=True
            )

            file_name = (
                os.path.splitext(
                    os.path.basename(self.image.name)
                )[0]
                + '.jpg'
            )

            self.image.save(
                file_name,
                ContentFile(buffer.getvalue()),
                save=False
            )

            super().save(update_fields=['image'])

        except Exception:
            pass

class PropertyInspectionReport(models.Model):
    """
    Formal inspection report prepared by Ensolanka staff
    based on a property maintenance visit.

    A visit may produce one inspection report.
    This report can later be published to the property owner.
    """

    CONDITION_STATUS_CHOICES = [
        ('excellent', 'Excellent'),
        ('good', 'Good'),
        ('fair', 'Fair'),
        ('needs_attention', 'Needs Attention'),
        ('critical', 'Critical'),
        ('not_applicable', 'Not Applicable'),
    ]

    REPORT_STATUS_CHOICES = [
        ('draft', 'Draft'),
        ('ready_for_review', 'Ready for Review'),
        ('published', 'Published to Owner'),
    ]

    managed_property = models.ForeignKey(
        ManagedProperty,
        on_delete=models.CASCADE,
        related_name='inspection_reports'
    )

    visit = models.OneToOneField(
        PropertyMaintenanceVisit,
        on_delete=models.CASCADE,
        related_name='inspection_report',
        help_text="The maintenance visit from which this inspection report was prepared."
    )

    report_title = models.CharField(
        max_length=255,
        help_text="Example: Monthly Property Inspection Report - June 2026."
    )

    report_status = models.CharField(
        max_length=30,
        choices=REPORT_STATUS_CHOICES,
        default='draft'
    )

    inspection_date = models.DateField(
        null=True,
        blank=True,
        help_text="Usually the visit date or actual inspection completion date."
    )

    overall_condition = models.CharField(
        max_length=40,
        choices=CONDITION_STATUS_CHOICES,
        default='good'
    )

    cleanliness_status = models.CharField(
        max_length=40,
        choices=CONDITION_STATUS_CHOICES,
        default='not_applicable'
    )

    garden_status = models.CharField(
        max_length=40,
        choices=CONDITION_STATUS_CHOICES,
        default='not_applicable'
    )

    security_status = models.CharField(
        max_length=40,
        choices=CONDITION_STATUS_CHOICES,
        default='not_applicable'
    )

    utility_status = models.CharField(
        max_length=40,
        choices=CONDITION_STATUS_CHOICES,
        default='not_applicable'
    )

    structural_status = models.CharField(
        max_length=40,
        choices=CONDITION_STATUS_CHOICES,
        default='not_applicable'
    )

    issues_found = models.TextField(
        blank=True,
        help_text="Describe any issues, defects, concerns, or unusual observations identified during inspection."
    )

    recommendations = models.TextField(
        blank=True,
        help_text="Recommended follow-up actions, further checks, repairs, or maintenance improvements."
    )

    urgent_action_required = models.BooleanField(
        default=False,
        help_text="Enable if immediate owner/staff attention is recommended."
    )

    owner_visible_summary = models.TextField(
        blank=True,
        help_text="Summary that may later be shown to the property owner in the report center."
    )

    internal_staff_note = models.TextField(
        blank=True,
        help_text="Internal note for Ensolanka staff only."
    )

    prepared_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='prepared_property_inspection_reports'
    )

    approved_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='approved_property_inspection_reports'
    )

    is_published_to_owner = models.BooleanField(
        default=False,
        help_text="If enabled, this report can later be displayed in the owner's report center."
    )

    published_at = models.DateTimeField(
        null=True,
        blank=True
    )

    created_at = models.DateTimeField(
        auto_now_add=True
    )

    updated_at = models.DateTimeField(
        auto_now=True
    )

    class Meta:
        ordering = ['-inspection_date', '-created_at']
        verbose_name = 'Property Inspection Report'
        verbose_name_plural = 'Property Inspection Reports'

    def __str__(self):
        return f"{self.report_title} - {self.managed_property.property_name}"

    def is_published(self):
        return self.report_status == 'published' or self.is_published_to_owner
    
class PropertyInspectionReportPhoto(models.Model):
    """
    Photos attached specifically to a formal inspection report.
    These are separate from raw visit photos so staff can curate
    owner-facing inspection evidence.
    """

    PHOTO_TYPE_CHOICES = [
        ('general_condition', 'General Condition'),
        ('issue_evidence', 'Issue Evidence'),
        ('cleanliness', 'Cleanliness'),
        ('garden', 'Garden / Outdoor'),
        ('security', 'Security'),
        ('utilities', 'Utilities'),
        ('structural', 'Structural'),
        ('recommendation_reference', 'Recommendation Reference'),
        ('other', 'Other'),
    ]

    report = models.ForeignKey(
        PropertyInspectionReport,
        on_delete=models.CASCADE,
        related_name='photos'
    )

    image = models.ImageField(
        upload_to='property_care/inspection_report_photos/',
        validators=[validate_image_file]
    )

    photo_type = models.CharField(
        max_length=40,
        choices=PHOTO_TYPE_CHOICES,
        default='general_condition'
    )

    caption = models.CharField(
        max_length=255,
        blank=True
    )

    is_owner_visible = models.BooleanField(
        default=True,
        help_text="If enabled, this photo can appear with the owner's inspection report."
    )

    uploaded_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='inspection_report_photos_uploaded'
    )

    uploaded_at = models.DateTimeField(
        auto_now_add=True
    )

    class Meta:
        ordering = ['-uploaded_at']
        verbose_name = 'Property Inspection Report Photo'
        verbose_name_plural = 'Property Inspection Report Photos'

    def __str__(self):
        return f"Inspection Report Photo - {self.report.report_title}"

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        if self.image:
            self.compress_image()

    def compress_image(self):
        try:
            img = Image.open(self.image.path)

            if img.mode in ('RGBA', 'P'):
                img = img.convert('RGB')

            max_width = 1600
            max_height = 1600
            img.thumbnail((max_width, max_height))

            buffer = BytesIO()
            img.save(
                buffer,
                format='JPEG',
                quality=85,
                optimize=True
            )

            file_name = (
                os.path.splitext(
                    os.path.basename(self.image.name)
                )[0]
                + '.jpg'
            )

            self.image.save(
                file_name,
                ContentFile(buffer.getvalue()),
                save=False
            )

            super().save(update_fields=['image'])

        except Exception:
            pass

class PropertyCareGuidanceResource(models.Model):
    LANGUAGE_CHOICES = [
        ('en', 'English'),
        ('si', 'Sinhala'),
        ('ta', 'Tamil'),
    ]

    language = models.CharField(
        max_length=2,
        choices=LANGUAGE_CHOICES,
        default='en',
        unique=True
    )

    title = models.CharField(
        max_length=200,
        default="Ensolanka Remote Property Care Guidance Playbook"
    )

    full_playbook_pdf = models.FileField(
        upload_to='property_care_guidance/playbooks/%Y/%m/',
        blank=True,
        null=True,
        help_text="Upload the full remote property care guidance playbook PDF."
    )

    summary_overview_pdf = models.FileField(
        upload_to='property_care_guidance/summaries/%Y/%m/',
        blank=True,
        null=True,
        help_text="Upload the summary overview or quick guidance PDF."
    )

    audio_guide_file = models.FileField(
        upload_to='property_care_guidance/audio/%Y/%m/',
        blank=True,
        null=True,
        help_text="Upload the audio guidance file, such as MP3."
    )

    youtube_video_link = models.URLField(
        blank=True,
        null=True,
        help_text="Optional YouTube or video guidance link."
    )

    description = models.TextField(
        blank=True,
        help_text="Brief description about this remote property care guidance resource."
    )

    is_active = models.BooleanField(default=True)

    created_at = models.DateTimeField(default=timezone.now)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['language']
        verbose_name = "Property Care Guidance Resource"
        verbose_name_plural = "Property Care Guidance Resources"

    def __str__(self):
        return f"{self.get_language_display()} - {self.title}"