import os

from galaxy.model.db.user import get_user_by_email
from galaxy.security.vault import UserVaultWrapper
from galaxy_test.base import api_asserts
from galaxy_test.base.populators import DatasetPopulator
from galaxy_test.driver import integration_util

SCRIPT_DIRECTORY = os.path.abspath(os.path.dirname(__file__))
FILE_SOURCES_VAULT_CONF = os.path.join(SCRIPT_DIRECTORY, "file_sources_conf_vault.yml")


class TestVaultFileSourceIntegration(integration_util.IntegrationTestCase, integration_util.ConfiguresDatabaseVault):
    dataset_populator: DatasetPopulator
    USER_1_APP_VAULT_ENTRY = "randomvaultuser1@universe.com"
    USER_2_APP_VAULT_ENTRY = "randomvaultuser2@universe.com"

    @classmethod
    def handle_galaxy_config_kwds(cls, config):
        super().handle_galaxy_config_kwds(config)
        cls._configure_database_vault(config)
        config["file_sources_config_file"] = FILE_SOURCES_VAULT_CONF
        config["user_library_import_symlink_allowlist"] = os.path.realpath(cls._test_driver.mkdtemp())

    def setUp(self):
        super().setUp()
        self.dataset_populator = DatasetPopulator(self.galaxy_interactor)

    def test_vault_secret_per_user_in_file_source(self):
        """
        This file source performs a user vault lookup. The secret stored for the first user is a
        valid path and should succeed, while the second user's stored secret should fail.
        """
        app = self._app

        with self._different_user(email=self.USER_1_APP_VAULT_ENTRY):
            user = get_user_by_email(self._app.model.session, self.USER_1_APP_VAULT_ENTRY)
            user_vault = UserVaultWrapper(app.vault, user)
            # use a valid symlink path so the posix list succeeds
            user_vault.write_secret("posix/root_path", app.config.user_library_import_symlink_allowlist[0])

            data = {"target": "gxfiles://test_user_vault"}
            list_response = self.galaxy_interactor.get("remote_files", data)
            api_asserts.assert_status_code_is_ok(list_response)
            remote_files = list_response.json()
            print(remote_files)

        with self._different_user(email=self.USER_2_APP_VAULT_ENTRY):
            user = get_user_by_email(self._app.model.session, self.USER_2_APP_VAULT_ENTRY)
            user_vault = UserVaultWrapper(app.vault, user)
            # use an invalid symlink path so the posix list fails
            user_vault.write_secret("posix/root_path", "/invalid/root")

            data = {"target": "gxfiles://test_user_vault"}
            list_response = self.galaxy_interactor.get("remote_files", data)
            api_asserts.assert_status_code_is(list_response, 404)

    def test_vault_secret_per_app_in_file_source(self):
        """
        This file source performs an app level vault lookup. Although the secret stored for the first user is a
        valid path and the second user's stored secret is invalid, we are performing an app level lookup
        which should succeed for both users.
        """
        # write app level secret
        app = self._app
        # use a valid symlink path so the posix list succeeds
        app.vault.write_secret("posix/root_path", app.config.user_library_import_symlink_allowlist[0])

        with self._different_user(email=self.USER_1_APP_VAULT_ENTRY):
            user = get_user_by_email(self._app.model.session, self.USER_1_APP_VAULT_ENTRY)
            user_vault = UserVaultWrapper(app.vault, user)
            # use a valid symlink path so the posix list succeeds
            user_vault.write_secret("posix/root_path", app.config.user_library_import_symlink_allowlist[0])

            data = {"target": "gxfiles://test_app_vault"}
            list_response = self.galaxy_interactor.get("remote_files", data)
            api_asserts.assert_status_code_is_ok(list_response)
            remote_files = list_response.json()
            print(remote_files)

        with self._different_user(email=self.USER_2_APP_VAULT_ENTRY):
            user = get_user_by_email(self._app.model.session, self.USER_2_APP_VAULT_ENTRY)
            user_vault = UserVaultWrapper(app.vault, user)
            # use an invalid symlink path so the posix list would fail if used
            user_vault.write_secret("posix/root_path", "/invalid/root")

            data = {"target": "gxfiles://test_app_vault"}
            list_response = self.galaxy_interactor.get("remote_files", data)
            api_asserts.assert_status_code_is_ok(list_response)
            remote_files = list_response.json()
            print(remote_files)

    def test_upload_file_from_remote_source(self):
        with self._different_user(email=self.USER_1_APP_VAULT_ENTRY):
            app = self._app
            user = get_user_by_email(self._app.model.session, self.USER_1_APP_VAULT_ENTRY)
            user_vault = UserVaultWrapper(app.vault, user)
            # use a valid symlink path so the posix list succeeds
            user_vault.write_secret("posix/root_path", app.config.user_library_import_symlink_allowlist[0])
            data = {"target": "gxfiles://test_user_vault"}
            with open(os.path.join(app.config.user_library_import_symlink_allowlist[0], "a_file"), "w") as fh:
                fh.write("I require access to the vault")
            list_response = self.galaxy_interactor.get("remote_files", data)
            api_asserts.assert_status_code_is_ok(list_response)
            remote_files = list_response.json()
            assert len(remote_files) == 1
            with self.dataset_populator.test_history() as history_id:
                element = dict(src="url", url="gxfiles://test_user_vault/a_file")
                target = {
                    "destination": {"type": "hdas"},
                    "elements": [element],
                }
                targets = [target]
                payload = {
                    "history_id": history_id,
                    "targets": targets,
                }
                new_dataset = self.dataset_populator.fetch(payload, assert_ok=True).json()["outputs"][0]
                content = self.dataset_populator.get_history_dataset_content(history_id, dataset=new_dataset)
                assert content == "I require access to the vault", content
