# (c) cavaliba.com - tests / data / export datetime second precision

from datetime import datetime

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

import app_home.cache as cache
from app_data.data import Instance
from app_data.models import DataInstance
from tests import helper

AAA = {"username": "testuser", "perms": ["p_data_admin"]}

SCHEMA = "dtprec"

# no fractional seconds, offset kept
ISO_SECONDS_RE = r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}$"


class TestDataExportDatetimeSecondPrecision(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_schema(
            classname=SCHEMA,
            field_definition={"mystring": {"dataformat": "string", "displayname": "MyString"}},
        )
        helper.add_instance(classname=SCHEMA, keyname="obj01", fields={"mystring": "v1"})

        # force microsecond-bearing timestamps straight into the DB: exports of
        # legacy rows written before the truncation must be clean too
        DataInstance.objects.filter(classname=SCHEMA, keyname="obj01").update(
            last_sync=timezone.make_aware(datetime(2026, 2, 15, 10, 11, 12, 123456)),
            last_update=timezone.make_aware(datetime(2026, 2, 15, 10, 11, 13, 654321)),
        )
        self.instance = Instance.from_keyname(SCHEMA, "obj01")

    def test_dict_export_has_no_fractional_seconds(self):
        export = self.instance.get_dict_for_export()
        self.assertRegex(export["last_sync"], ISO_SECONDS_RE)
        self.assertRegex(export["last_update"], ISO_SECONDS_RE)
        self.assertNotIn(".", export["last_sync"])
        self.assertNotIn(".", export["last_update"])

    def test_dict_export_keeps_whole_second_value(self):
        export = self.instance.get_dict_for_export()
        # truncation, not rounding: .123456 and .654321 both drop (the exported
        # string is UTC-based, so compare instants rather than a literal)
        self.assertEqual(
            datetime.fromisoformat(export["last_sync"]),
            timezone.make_aware(datetime(2026, 2, 15, 10, 11, 12)),
        )
        self.assertEqual(
            datetime.fromisoformat(export["last_update"]),
            timezone.make_aware(datetime(2026, 2, 15, 10, 11, 13)),
        )

    def test_csv_line_has_no_fractional_seconds(self):
        columns = self.instance.get_csv_columns()
        line = self.instance.get_csv_line(columns)
        for name in ("last_sync", "last_update"):
            cell = line[columns.index(name)]
            self.assertRegex(cell, ISO_SECONDS_RE)
            self.assertNotIn(".", cell)

    def test_exported_last_sync_reimports(self):
        # the offset must survive the truncation: merge_import() silently drops a
        # naive last_sync string
        export = self.instance.get_dict_for_export()
        other = Instance(classname=SCHEMA)
        other.merge_import(
            {"classname": SCHEMA, "keyname": "obj02", "last_sync": export["last_sync"]}, aaa=AAA
        )
        self.assertIsNotNone(other.last_sync)
        self.assertEqual(other.last_sync.microsecond, 0)
        self.assertEqual(other.last_sync, timezone.make_aware(datetime(2026, 2, 15, 10, 11, 12)))

    def test_reimport_of_subsecond_value_is_truncated(self):
        other = Instance(classname=SCHEMA)
        other.merge_import(
            {
                "classname": SCHEMA,
                "keyname": "obj03",
                "last_sync": "2026-02-15T10:11:12.987654+00:00",
            },
            aaa=AAA,
        )
        self.assertIsNotNone(other.last_sync)
        self.assertEqual(other.last_sync.microsecond, 0)
        self.assertEqual(other.last_sync.second, 12)
