# (c) cavaliba.com - tests / data / export last_sync and last_update

import json

from django.test import TestCase, override_settings
from django.urls import reverse
from django.utils import timezone

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

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


class TestExportLastSyncLastUpdate(TestCase):
    def setUp(self):
        cache.clear()
        helper.add_admin_user(login="unittest")
        helper.add_schema(
            classname="expsync",
            field_definition={
                "mystring": {"dataformat": "string", "displayname": "MyString"},
            },
        )

        instance = Instance(classname="expsync")
        instance.merge_import({"classname": "expsync", "keyname": "expsync-01"}, aaa=AAA)
        instance.last_sync = timezone.now()
        instance.save(aaa=AAA, action="create")

        helper.add_instance(
            classname="expsync",
            keyname="expsync-02",
            fields={"mystring": "no sync"},
        )

    def _post(self, extra=None):
        data = {
            "schema": "expsync",
            "query": "",
        }
        if extra:
            data.update(extra)
        return self.client.post(reverse("app_data:data_exporter"), data)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_json_export_no_dataview_does_not_crash(self):
        # no explicit "expsync_default" dataview -> DataView() builtin fallback,
        # whose columns include last_update -> used to crash json.dumps()
        response = self._post({"format": "json"})
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        row = next(item for item in data if item["keyname"] == "expsync-01")
        self.assertIn("T", row["last_update"])

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_yaml_export_no_dataview_isoformat(self):
        # no explicit "expsync_default" dataview -> DataView() builtin fallback
        # (columns keyname/displayname/last_update) - value must be ISO ('T'
        # separator), not the old space-separated raw datetime repr
        response = self._post({"format": "yaml"})
        self.assertEqual(response.status_code, 200)
        content = response.content.decode()
        self.assertRegex(content, r"last_update: '?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}")

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_csv_export_no_dataview_isoformat(self):
        # builtin fallback dataview also carries last_update as a column
        response = self._post({"format": "csv"})
        self.assertEqual(response.status_code, 200)
        content = response.content.decode()
        header = content.strip().splitlines()[0].split(",")
        self.assertIn("last_update", header)
        idx = header.index("last_update")
        rows = content.strip().splitlines()[1:]
        for row in rows:
            cell = row.split(",")[idx]
            self.assertIn("T", cell)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_plain_csv_all_columns_includes_last_sync_and_last_update(self):
        response = self._post({"format": "csv"})
        self.assertEqual(response.status_code, 200)
        content = response.content.decode()
        lines = content.strip().splitlines()
        header = lines[0].split(",")
        self.assertIn("last_sync", header)
        self.assertIn("last_update", header)

        idx_keyname = header.index("keyname")
        idx_last_sync = header.index("last_sync")
        idx_last_update = header.index("last_update")

        rows = {line.split(",")[idx_keyname]: line.split(",") for line in lines[1:]}

        # expsync-01 was synced -> non-empty, ISO-formatted last_sync
        self.assertIn("T", rows["expsync-01"][idx_last_sync])
        self.assertIn("T", rows["expsync-01"][idx_last_update])

        # expsync-02 was never synced -> empty last_sync cell, but last_update is
        # always set on save
        self.assertEqual(rows["expsync-02"][idx_last_sync], "")
        self.assertIn("T", rows["expsync-02"][idx_last_update])

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_plain_csv_fields_filter_excludes_last_sync_last_update(self):
        response = self._post({"format": "csv", "columns": "!last_sync,last_update"})
        self.assertEqual(response.status_code, 200)
        content = response.content.decode()
        header = content.strip().splitlines()[0].split(",")
        self.assertNotIn("last_sync", header)
        self.assertNotIn("last_update", header)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_plain_json_export_still_omits_null_last_sync(self):
        # get_dict_for_export() null-omission behavior is unchanged
        response = self._post({"format": "json"})
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.content)
        row2 = next(item for item in data if item["keyname"] == "expsync-02")
        self.assertNotIn("last_sync", row2)
        row1 = next(item for item in data if item["keyname"] == "expsync-01")
        self.assertIn("last_sync", row1)
