# (c) cavaliba.com - tests / builtin/demo/500_fulltest.yml

"""
500_fulltest.yml is the demo schema that carries every dataformat and the
dataformat_ext / cardinal_max / default_value / subfield combinations. It is
only useful while it stays exhaustive and actually loads, so this pins both:
every dataformat in FIELD_CONSTRUCTOR_TABLE must appear in the schema, and the
instances must come back with their multi-values, defaults, injected enumerate
subfields and resolved external fields.

Loads the real builtin/demo folder (sorted single pass, same as a factory reset
with demo data), since fulltest references site/laptop/app/user/group/role and
the shared country_iso enumerate.
"""

from django.test import TestCase

import app_home.cache as cache
from app_data.data import FIELD_CONSTRUCTOR_TABLE, Instance
from app_data.schema import Schema
from app_data.search import get_instance_from_advanced_query
from app_home.factory import load_demo

CLASSNAME = "fulltest"


class TestDemoFullTest(TestCase):
    @classmethod
    def setUpTestData(cls):
        cache.clear()
        cls.report = load_demo()

    def setUp(self):
        cache.clear()

    def test_demo_folder_loads_without_error(self):
        self.assertEqual(self.report["errors"], [])

    def test_schema_covers_every_dataformat(self):
        schema = Schema.from_name(CLASSNAME)
        self.assertIsNotNone(schema)

        seen = {f["dataformat"] for f in schema.fields.values()}
        expected = set(FIELD_CONSTRUCTOR_TABLE) - {"unknown"}

        self.assertEqual(expected - seen, set(), "dataformat missing from 500_fulltest.yml")

    def test_schema_covers_the_option_combinations(self):
        schema = Schema.from_name(CLASSNAME)
        fields = schema.fields

        # multi-valued, default_value, dataformat_ext, mandatory
        self.assertEqual(fields["f_string_multi"]["cardinal_max"], 0)
        self.assertEqual(fields["f_string_default"]["default_value"], "Not assessed")
        self.assertEqual(fields["f_string_safe"]["dataformat_ext"], "safe")
        self.assertEqual(fields["f_ipv4_subnet_strict"]["dataformat_ext"], "subnet strict")
        self.assertEqual(fields["f_int_range"]["dataformat_ext"], "gte_0 lte_100")
        self.assertEqual(fields["f_string_mandatory"]["cardinal_min"], 1)

    def test_fully_populated_instance(self):
        instance = Instance.from_keyname(classname=CLASSNAME, keyname="assess01", expand=True)
        self.assertIsNotNone(instance)

        self.assertEqual(instance.get_attribute_first("f_int_range"), 94)
        self.assertEqual(
            instance.get_attribute("f_string_multi"), ["ward-3", "cardiology", "annual"]
        )
        self.assertEqual(instance.get_attribute_first("f_grade"), "A")
        self.assertEqual(instance.get_attribute_first("f_ipv4_subnet"), "10.11.1.0/24")

    def test_enumerate_subfields_are_injected(self):
        instance = Instance.from_keyname(classname=CLASSNAME, keyname="assess01", expand=True)

        self.assertIn("f_grade__label", instance.fields)
        self.assertEqual(instance.get_attribute_first("f_grade__label"), "Excellent")
        self.assertEqual(instance.get_attribute_first("f_grade__score_min"), 90)

    def test_schema_subfields_are_injected(self):
        instance = Instance.from_keyname(classname=CLASSNAME, keyname="assess01", expand=True)

        self.assertIn("f_site__city", instance.fields)
        self.assertEqual(instance.get_attribute_first("f_site__city"), "Paris")

    def test_external_field_chains_through_a_remote_reference(self):
        # f_laptop -> laptop.hosting -> site, injected as f_laptop_site, then its
        # own "city" subfield. external only chains *schema* references, so the
        # remote fieldname must be one (here laptop.hosting), never a plain string
        instance = Instance.from_keyname(classname=CLASSNAME, keyname="assess01", expand=True)

        self.assertIn("f_laptop_site", instance.fields)
        self.assertIn("f_laptop_site__city", instance.fields)
        self.assertEqual(instance.get_attribute_first("f_laptop_site__city"), "Paris")

    def test_mostly_empty_instance_falls_back_to_defaults(self):
        instance = Instance.from_keyname(classname=CLASSNAME, keyname="assess03", expand=True)
        self.assertIsNotNone(instance)

        self.assertEqual(instance.get_attribute_first("f_grade"), "unset")
        # a schema field resolves to the referenced instance, not its keyname
        self.assertEqual(instance.get_attribute_first("f_site").keyname, "MADRD")

    def test_dataviews_target_the_schema(self):
        for keyname in ("fulltest_default", "fulltest_action"):
            dv = Instance.from_keyname(classname="_dataview", keyname=keyname)
            self.assertIsNotNone(dv, keyname)
            self.assertEqual(dv.get_attribute_first("target_class"), CLASSNAME)

    def test_action_dataview_query_actually_matches(self):
        # two traps this pins: the query must filter on a stored field (an
        # injected subfield like f_grade__audit_required is computed at read
        # time, never indexed, and would match nothing), and a field search is a
        # substring match - hence the enumerate's "unset" value, since "pending"
        # would be caught by the "f_grade:D" half of the query
        dv = Instance.from_keyname(classname="_dataview", keyname="fulltest_action")
        query = dv.get_attribute_first("query")
        self.assertTrue(query)

        keynames = {
            iobj.keyname
            for iobj in get_instance_from_advanced_query(classname=CLASSNAME, query=query)
        }
        self.assertEqual(keynames, {"assess02"})
