# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals

from logging import getLogger
import os
from os.path import isdir, join, lexists
from tempfile import gettempdir
from unittest import TestCase
from uuid import uuid4

from conda.auxlib.collection import AttrDict
from conda.base.constants import PREFIX_MAGIC_FILE
from conda.base.context import context, reset_context, conda_tests_ctxt_mgmt_def_pol
from conda.common.io import env_var
from conda.common.path import paths_equal
from conda.core.envs_manager import list_all_known_prefixes, register_env, \
    get_user_environments_txt_file, \
    unregister_env, _clean_environments_txt
from conda.gateways.disk import mkdir_p
from conda.gateways.disk.delete import rm_rf
from conda.gateways.disk.read import yield_lines
from conda.gateways.disk.update import touch

import pytest

try:
    from unittest.mock import patch
except ImportError:
    from mock import patch

log = getLogger(__name__)


class EnvsManagerUnitTests(TestCase):

    def setUp(self):
        tempdirdir = gettempdir()
        dirname = str(uuid4())[:8]
        self.prefix = join(tempdirdir, dirname)
        mkdir_p(self.prefix)
        assert isdir(self.prefix)


    def tearDown(self):
        rm_rf(self.prefix)
        assert not lexists(self.prefix)

    def test_register_unregister_location_env(self):
        user_environments_txt_file = get_user_environments_txt_file()
        if (not os.path.exists(user_environments_txt_file)
            or user_environments_txt_file == os.devnull):
            pytest.skip('user environments.txt file {} does not exist'.format(user_environments_txt_file))

        gascon_location = join(self.prefix, 'gascon')
        touch(join(gascon_location, PREFIX_MAGIC_FILE), mkdir=True)
        assert gascon_location not in list_all_known_prefixes()

        touch(user_environments_txt_file, mkdir=True, sudo_safe=True)
        register_env(gascon_location)
        assert gascon_location in yield_lines(user_environments_txt_file)
        assert len(tuple(x for x in yield_lines(user_environments_txt_file) if paths_equal(gascon_location, x))) == 1

        register_env(gascon_location)  # should be completely idempotent
        assert len(tuple(x for x in yield_lines(user_environments_txt_file) if x == gascon_location)) == 1

        unregister_env(gascon_location)
        assert gascon_location not in list_all_known_prefixes()
        unregister_env(gascon_location)  # should be idempotent
        assert gascon_location not in list_all_known_prefixes()

    def test_prefix_cli_flag(self):
        envs_dirs = (join(self.prefix, 'first-envs-dir'), join(self.prefix, 'seconds-envs-dir'))
        with env_var('CONDA_ENVS_DIRS', os.pathsep.join(envs_dirs), stack_callback=conda_tests_ctxt_mgmt_def_pol):

            # even if prefix doesn't exist, it can be a target prefix
            reset_context((), argparse_args=AttrDict(prefix='./blarg', func='create'))
            target_prefix = join(os.getcwd(), 'blarg')
            assert context.target_prefix == target_prefix
            assert not isdir(target_prefix)

    def test_rewrite_environments_txt_file(self):
        mkdir_p(join(self.prefix, 'conda-meta'))
        touch(join(self.prefix, 'conda-meta', 'history'))
        doesnt_exist = join(self.prefix, 'blarg')
        environments_txt_path = join(self.prefix, 'environments.txt')
        with open(environments_txt_path, 'w') as fh:
            fh.write(self.prefix + '\n')
            fh.write(doesnt_exist + '\n')
        cleaned_1 = _clean_environments_txt(environments_txt_path)
        assert cleaned_1 == (self.prefix,)
        with patch('conda.core.envs_manager._rewrite_environments_txt') as _rewrite_patch:
            cleaned_2 = _clean_environments_txt(environments_txt_path)
            assert cleaned_2 == (self.prefix,)
            assert _rewrite_patch.call_count == 0


@patch("conda.core.envs_manager.context")
@patch("conda.core.envs_manager.get_user_environments_txt_file")
@patch("conda.core.envs_manager._clean_environments_txt")
def test_list_all_known_prefixes_with_permission_error(mock_clean_env, mock_get_user_env, mock_context, tmp_path):
    # Mock context
    myenv_dir = tmp_path / "envs"
    myenv_dir.mkdir()
    mock_context.envs_dirs = str(myenv_dir)
    mock_context.root_prefix = "root_prefix"
    # Mock get_user_environments_txt_file to return a file
    env_txt_file = tmp_path / "environment.txt"
    touch(env_txt_file)
    mock_get_user_env.return_value = env_txt_file
    # Mock _clean_environments_txt to raise PermissionError
    mock_clean_env.side_effect = PermissionError()
    all_env_paths = list_all_known_prefixes()
    # On Windows, all_env_paths can contain more paths (like '\\Miniconda')
    assert "root_prefix" in all_env_paths
