# (c) cavaliba.com - tests - search datetime meta fields (last_sync, last_update)

from datetime import datetime

from django.test import TestCase
from django.utils import timezone

import app_home.cache as cache
from app_data.models import DataInstance
from app_data.search import get_instance_from_advanced_query
from tests.helper import add_instance, add_schema

SCHEMA = "srch_dt_test"

FIELD_DEF = {
    "city": {"displayname": "City", "dataformat": "string"},
}


def _set_datetime_columns(keyname, last_sync=None, last_update=None):
    DataInstance.objects.filter(classname=SCHEMA, keyname=keyname).update(
        last_sync=last_sync, last_update=last_update
    )


class SearchDatetimeMetaFieldTest(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        add_schema(SCHEMA, field_definition=FIELD_DEF)
        add_instance(SCHEMA, "paris", fields={"city": "Paris"})
        add_instance(SCHEMA, "lyon", fields={"city": "Lyon"})
        add_instance(SCHEMA, "toulouse", fields={"city": "Toulouse"})

        _set_datetime_columns(
            "paris",
            last_sync=timezone.make_aware(datetime(2026, 1, 15, 10, 0, 0)),
            last_update=timezone.make_aware(datetime(2026, 1, 15, 10, 0, 0)),
        )
        _set_datetime_columns(
            "lyon",
            last_sync=timezone.make_aware(datetime(2026, 3, 1, 8, 0, 0)),
            last_update=timezone.make_aware(datetime(2026, 3, 1, 8, 0, 0)),
        )
        # toulouse: force last_sync/last_update to null (last_update is auto-set on
        # every save, so it must be explicitly cleared to test null-exclusion)
        _set_datetime_columns("toulouse", last_sync=None, last_update=None)

    def setUp(self):
        cache.clear()

    def _keynames(self, qs):
        return set(qs.values_list("keyname", flat=True))

    def _q(self, query):
        return get_instance_from_advanced_query(query=query, classname=SCHEMA)

    def test_exact_day_match(self):
        qs = self._q("last_sync:2026-01-15")
        self.assertEqual(self._keynames(qs), {"paris"})

    def test_exact_day_no_match(self):
        qs = self._q("last_sync:2026-01-16")
        self.assertEqual(qs.count(), 0)

    def test_gte_comparison(self):
        qs = self._q("last_sync:>=2026-02-01")
        self.assertEqual(self._keynames(qs), {"lyon"})

    def test_lt_comparison(self):
        qs = self._q("last_sync:<2026-02-01")
        self.assertEqual(self._keynames(qs), {"paris"})

    def test_not_modifier(self):
        qs = self._q("NOT last_sync:2026-01-15")
        self.assertNotIn("paris", self._keynames(qs))
        self.assertIn("lyon", self._keynames(qs))

    def test_invalid_date_returns_no_match_without_error(self):
        qs = self._q("last_sync:not-a-date")
        self.assertEqual(qs.count(), 0)

    def test_last_update_field(self):
        qs = self._q("last_update:>=2026-02-01")
        self.assertEqual(self._keynames(qs), {"lyon"})

    def test_null_last_sync_excluded_from_comparison(self):
        qs = self._q("last_sync:>=2000-01-01")
        self.assertEqual(self._keynames(qs), {"paris", "lyon"})
        self.assertNotIn("toulouse", self._keynames(qs))

    def test_exists(self):
        qs = self._q("EXISTS:last_sync")
        self.assertEqual(self._keynames(qs), {"paris", "lyon"})

    def test_not_exists(self):
        qs = self._q("NOT EXISTS:last_sync")
        self.assertEqual(self._keynames(qs), {"toulouse"})

    def test_empty(self):
        qs = self._q("EMPTY:last_sync")
        self.assertEqual(self._keynames(qs), {"toulouse"})

    def test_not_empty(self):
        qs = self._q("NOT EMPTY:last_sync")
        self.assertEqual(self._keynames(qs), {"paris", "lyon"})
