# (c) cavaliba.com - tests / api import - multi-item batch fix

import json

import yaml
from django.test import TestCase

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


class ApiImportMultiTest(TestCase):
    """Regression coverage for the /api/import/ N^2 bug: index() used to call
    load_broker(datalist=datalist, ...) *inside* the per-item loop (reprocessing the
    whole batch on every iteration instead of just the current item), which also made
    "discard" a no-op (a discarded item still got created via a sibling iteration's
    full-list reload) and crashed with UnboundLocalError whenever every item was
    discarded (or the batch was empty)."""

    def setUp(self):
        cache.clear()
        helper.add_schema(
            classname="apimultitest",
            field_definition={"mystring": {"dataformat": "string", "displayname": "MyString"}},
        )
        self.headers = helper.add_apikey_admin()

    def _post_import(self, body, content_type="application/json", params=""):
        url = f"/api/import/{params}"
        return self.client.post(url, data=body, content_type=content_type, headers=self.headers)

    def test_multi_item_import_creates_all_items_once(self):
        body = json.dumps(
            [
                {"classname": "apimultitest", "keyname": "row1", "mystring": "a"},
                {"classname": "apimultitest", "keyname": "row2", "mystring": "b"},
                {"classname": "apimultitest", "keyname": "row3", "mystring": "c"},
            ]
        )
        response = self._post_import(body)
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertEqual(data["count"], 3)
        self.assertEqual(data["count_ok"], 3)
        for keyname in ("row1", "row2", "row3"):
            self.assertIsNotNone(
                Instance.from_keyname(classname="apimultitest", keyname=keyname, expand=False)
            )

    def test_empty_list_does_not_crash(self):
        response = self._post_import("[]")
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json()["count"], 0)

    def test_pipeline_discard_all_does_not_crash(self):
        datalist = yaml.safe_load("""
            - classname: _pipeline
              keyname: pipeline_discard_all
              displayname: pipeline_discard_all
              is_enabled: True
              content: |
                    tasks:
                    - discard: ['']
            """)
        load_broker(datalist=datalist, aaa={"perms": ["p_pipeline_create"]})

        body = json.dumps(
            [
                {"classname": "apimultitest", "keyname": "rowA", "mystring": "a"},
                {"classname": "apimultitest", "keyname": "rowB", "mystring": "b"},
            ]
        )
        response = self._post_import(body, params="?pipeline=pipeline_discard_all")
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json()["count"], 0)
        self.assertIsNone(
            Instance.from_keyname(classname="apimultitest", keyname="rowA", expand=False)
        )
        self.assertIsNone(
            Instance.from_keyname(classname="apimultitest", keyname="rowB", expand=False)
        )

    def test_pipeline_discard_one_item_excludes_only_that_item(self):
        """A discarded item must not be re-created via a sibling iteration's
        full-list reload - the core N^2 bug."""

        datalist = yaml.safe_load("""
            - classname: _pipeline
              keyname: pipeline_discard_one
              displayname: pipeline_discard_one
              is_enabled: True
              content: |
                    tasks:
                    - set_condition: [SKIP, field_match, keyname, '^skipme$']
                    - discard: [SKIP]
            """)
        load_broker(datalist=datalist, aaa={"perms": ["p_pipeline_create"]})

        body = json.dumps(
            [
                {"classname": "apimultitest", "keyname": "skipme", "mystring": "a"},
                {"classname": "apimultitest", "keyname": "keepme", "mystring": "b"},
            ]
        )
        response = self._post_import(body, params="?pipeline=pipeline_discard_one")
        self.assertEqual(response.status_code, 200)
        data = response.json()
        self.assertEqual(data["count"], 1)
        self.assertEqual(data["count_ok"], 1)
        self.assertIsNone(
            Instance.from_keyname(classname="apimultitest", keyname="skipme", expand=False)
        )
        self.assertIsNotNone(
            Instance.from_keyname(classname="apimultitest", keyname="keepme", expand=False)
        )
