from django.db import models
from django.utils.translation import gettext_lazy as _

from servala.core.models.mixins import ServalaModelMixin


class OdooObjectCache(ServalaModelMixin):
    """
    Generic cache for Odoo API responses.

    Caches data from various Odoo models (product.product, product.template, uom.uom, etc.)
    to reduce API calls and improve performance.
    """

    odoo_model = models.CharField(
        max_length=100,
        verbose_name=_("Odoo model"),
        help_text=_(
            "Odoo model name: 'product.product', 'product.template', 'uom.uom', etc."
        ),
    )
    odoo_id = models.PositiveIntegerField(
        verbose_name=_("Odoo ID"),
        help_text=_("ID in the Odoo model"),
    )
    data = models.JSONField(
        verbose_name=_("Cached data"),
        help_text=_("Cached Odoo data including price, reporting_product_id, etc."),
    )
    expires_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_("Expires at"),
        help_text=_("When cache should be refreshed (null = never expires)"),
    )

    class Meta:
        verbose_name = _("Odoo Object Cache")
        verbose_name_plural = _("Odoo Object Caches")
        unique_together = [["odoo_model", "odoo_id"]]
        indexes = [
            models.Index(fields=["odoo_model", "odoo_id"]),
            models.Index(fields=["expires_at"]),
        ]

    def __str__(self):
        return f"{self.odoo_model}({self.odoo_id})"

    def is_expired(self):
        """Check if cache needs refresh."""
        if self.expires_at is None:
            return False
        from django.utils import timezone

        return timezone.now() > self.expires_at

    @classmethod
    def get_or_fetch(cls, odoo_model, odoo_id, ttl_hours=24):
        """
        Get cached data or fetch from Odoo if expired/missing.

        Args:
            odoo_model: Odoo model name (e.g., 'product.product')
            odoo_id: ID in the Odoo model
            ttl_hours: Time-to-live in hours for the cache

        Returns:
            OdooObjectCache instance with fresh data
        """
        from datetime import timedelta

        from django.utils import timezone

        try:
            cache_obj = cls.objects.get(odoo_model=odoo_model, odoo_id=odoo_id)
            if not cache_obj.is_expired():
                return cache_obj
            # Cache exists but expired, refresh it
            cache_obj.fetch_and_update(ttl_hours=ttl_hours)
            return cache_obj
        except cls.DoesNotExist:
            # Create new cache entry
            cache_obj = cls.objects.create(
                odoo_model=odoo_model,
                odoo_id=odoo_id,
                data={},
                expires_at=(
                    timezone.now() + timedelta(hours=ttl_hours) if ttl_hours else None
                ),
            )
            cache_obj.fetch_and_update(ttl_hours=ttl_hours)
            return cache_obj

    def fetch_and_update(self, ttl_hours=24):
        """
        Fetch latest data from Odoo and update cache.

        Args:
            ttl_hours: Time-to-live in hours for the cache
        """
        from datetime import timedelta

        from django.utils import timezone

        from servala.core.odoo import CLIENT

        # Fetch data from Odoo
        results = CLIENT.search_read(
            self.odoo_model,
            [[("id", "=", self.odoo_id)]],
            fields=None,  # Fetch all fields
        )

        if results:
            self.data = results[0]
            self.expires_at = (
                timezone.now() + timedelta(hours=ttl_hours) if ttl_hours else None
            )
            self.save(update_fields=["data", "expires_at", "updated_at"])
        else:
            # Object not found in Odoo, mark as expired immediately
            self.data = {}
            self.expires_at = timezone.now()
            self.save(update_fields=["data", "expires_at", "updated_at"])
