import os
import shutil
import tempfile
from flask import json
from unittest.mock import patch

from apps.prepopulate.app_initialize import AppInitializeWithDataCommand
from apps.prepopulate.app_scaffold_data import AppScaffoldDataCommand
from apps.prepopulate.app_initialize import fillEnvironmentVariables
from superdesk import get_resource_service, app
from superdesk.tests import TestCase


class AppInitializeWithDataCommandTestCase(TestCase):
    def _run(self, *a, **kw):
        command = AppInitializeWithDataCommand()
        return command.run(*a, **kw)

    def test_app_initialization(self):
        result = self._run()
        self.assertEqual(result, 0)

    def test_app_initialization_multiple_loads(self):
        result = self._run()
        self.assertEqual(result, 0)
        result = self._run()
        self.assertEqual(result, 0)

    def data_scaffolding_test(self):
        result = self._run(["desks", "stages"], sample_data=True)
        self.assertEqual(result, 0)

        docs = [
            {
                "_id": str(x),
                "type": "text",
                "abstract": "test abstract {}".format(x),
                "headline": "test headline {}".format(x),
                "body_html": "test long story body {}".format(x),
                "state": "published",
            }
            for x in range(0, 40)
        ]
        get_resource_service("published").post(docs)

        stories_per_desk = 2
        existing_desks = 18
        command = AppScaffoldDataCommand()
        result = command.run(stories_per_desk)
        self.assertEqual(result, 0)

        cursor = get_resource_service("desks").get_from_mongo(None, {})
        self.assertEqual(cursor.count(), existing_desks)

        cursor = get_resource_service("archive").get_from_mongo(None, {})
        self.assertEqual(cursor.count(), existing_desks * stories_per_desk)

    def test_sample_data(self):
        result = self._run(sample_data=True)
        self.assertEqual(result, 0)

        cursor = get_resource_service("desks").get_from_mongo(None, {})
        self.assertEqual(cursor.count(), 18)

    def test_app_initialization_index_creation(self):
        result = self._run()
        self.assertEqual(result, 0)
        result = app.data.mongo.pymongo(resource="archive").db["archive"].index_information()
        self.assertTrue("groups.refs.residRef_1" in result)
        self.assertTrue(result["groups.refs.residRef_1"]["sparse"])

    @patch.dict(os.environ, {"REUTERS_USERNAME": "r_u", "REUTERS_PASSWORD": "r_p"})
    def test_app_initialization_set_env_variables(self):
        item = {"username": "#ENV_REUTERS_USERNAME#", "password": "#ENV_REUTERS_PASSWORD#"}
        crt_item = fillEnvironmentVariables(item)
        self.assertEqual(crt_item["username"], "r_u")
        self.assertEqual(crt_item["password"], "r_p")

    @patch.dict(os.environ, {"REUTERS_USERNAME": "", "REUTERS_PASSWORD": "r_p"})
    def test_app_initialization_notset_env_variables(self):
        item = {"username": "#ENV_REUTERS_USERNAME#", "password": "#ENV_REUTERS_PASSWORD#"}
        crt_item = fillEnvironmentVariables(item)
        self.assertTrue(not crt_item)

    def test_init_keeps_user_modifications(self):
        self._run(["vocabularies"])
        urgency = self.app.data.find_one("vocabularies", req=None, _id="urgency")
        self.assertIsNotNone(urgency)
        self.assertEqual("init", urgency["_etag"])

        updates = {"display_name": "FOO"}
        self.app.data.update("vocabularies", "urgency", updates, urgency)

        self._run(["vocabularies"])
        urgency = self.app.data.find_one("vocabularies", req=None, _id="urgency")
        self.assertEqual("FOO", urgency["display_name"])
        self.assertNotEqual("init", urgency["_etag"])

        self._run(["vocabularies"], None, None, True)
        urgency = self.app.data.find_one("vocabularies", req=None, _id="urgency")
        self.assertEqual("Urgency", urgency["display_name"])
        self.assertEqual("init", urgency["_etag"])

    def test_init_can_combine_files_from_folders(self):
        init_dir = tempfile.mkdtemp("init", "test")
        self.app.config.update({"INIT_DATA_PATH": init_dir})

        with open(os.path.join(init_dir, "vocabularies.json"), "w") as f:
            f.write(json.dumps([{"_id": "foo"}]))
            f.flush()

        self._run(["vocabularies"])
        self.assertEqual(self.app.data.find("vocabularies", req=None, lookup={})[0].count(), 1)

        self._run(["validators"])
        self.assertGreater(self.app.data.find("validators", req=None, lookup={})[0].count(), 0)

        self.app.config.pop("INIT_DATA_PATH", None)
        shutil.rmtree(init_dir)
