import os
import shutil
import subprocess
import tempfile
from testtools import TestCase
from mock import (
    MagicMock,
    patch,
)
from charmhelpers.core.host import chdir

from urllib.parse import urlparse


try:
    from charmhelpers.fetch import (
        giturl,
        UnhandledSource,
    )
except ImportError:
    giturl = None
    UnhandledSource = None


class GitUrlFetchHandlerTest(TestCase):
    def setUp(self):
        super(GitUrlFetchHandlerTest, self).setUp()
        self.valid_urls = (
            "http://example.com/git-branch",
            "https://example.com/git-branch",
            "git://example.com/git-branch",
        )
        self.invalid_urls = (
            "file://example.com/foo.tar.bz2",
            "abc:example",
            "garbage",
        )
        self.fh = giturl.GitUrlFetchHandler()

    def test_handles_git_urls(self):
        for url in self.valid_urls:
            result = self.fh.can_handle(url)
            self.assertEqual(result, True, url)
        for url in self.invalid_urls:
            result = self.fh.can_handle(url)
            self.assertNotEqual(result, True, url)

    @patch.object(giturl, 'check_output')
    def test_clone(self, check_output):
        dest_path = "/destination/path"
        branch = "master"
        for url in self.valid_urls:
            self.fh.remote_branch = MagicMock()
            self.fh.load_plugins = MagicMock()
            self.fh.clone(url, dest_path, branch, None)

            check_output.assert_called_with(
                ['git', 'clone', url, dest_path, '--branch', branch], stderr=-2)

        for url in self.invalid_urls:
            with patch.dict('os.environ', {'CHARM_DIR': 'foo'}):
                self.assertRaises(UnhandledSource, self.fh.clone, url,
                                  dest_path, None,
                                  branch)

    def test_clone_functional(self):
        src = None
        dst = None
        try:
            src = tempfile.mkdtemp()
            with chdir(src):
                subprocess.check_output(['git', 'init'])
                subprocess.check_output(['git', 'config', 'user.name', 'Joe'])
                subprocess.check_output(
                    ['git', 'config', 'user.email', 'joe@test.com'])
                subprocess.check_output(['touch', 'foo'])
                subprocess.check_output(['git', 'add', 'foo'])
                subprocess.check_output(['git', 'commit', '-m', 'test'])
            dst = tempfile.mkdtemp()
            os.rmdir(dst)
            self.fh.clone(src, dst)
            assert os.path.exists(os.path.join(dst, '.git'))
            self.fh.clone(src, dst)  # idempotent
            assert os.path.exists(os.path.join(dst, '.git'))
        finally:
            if src:
                shutil.rmtree(src, ignore_errors=True)
            if dst:
                shutil.rmtree(dst, ignore_errors=True)

    def test_installs(self):
        self.fh.clone = MagicMock()

        for url in self.valid_urls:
            branch_name = urlparse(url).path.strip("/").split("/")[-1]
            dest = os.path.join('foo', 'fetched',
                                os.path.basename(branch_name))
            with patch.dict('os.environ', {'CHARM_DIR': 'foo'}):
                where = self.fh.install(url)
            self.assertEqual(where, dest)

    def test_installs_specified_dest(self):
        self.fh.clone = MagicMock()

        for url in self.valid_urls:
            branch_name = urlparse(url).path.strip("/").split("/")[-1]
            dest_repo = os.path.join('/tmp/git/',
                                     os.path.basename(branch_name))
            with patch.dict('os.environ', {'CHARM_DIR': 'foo'}):
                where = self.fh.install(url, dest="/tmp/git")
            self.assertEqual(where, dest_repo)
