from unittest import mock
import io
import os
import pathlib
import unittest
import yaml
import zipfile
from tempfile import TemporaryDirectory

import pytest
import responses

from ..source import GitHubSource
from ..source import LocalFolderSource
from cumulusci.core.config import UniversalConfig
from cumulusci.core.config import BaseProjectConfig
from cumulusci.core.config import ServiceConfig
from cumulusci.core.exceptions import DependencyResolutionError
from cumulusci.core.keychain import BaseProjectKeychain
from cumulusci.tasks.release_notes.tests.utils import MockUtil
from cumulusci.utils import temporary_dir
from cumulusci.utils import touch


class TestGitHubSource(unittest.TestCase, MockUtil):
    def setUp(self):
        self.repo_api_url = "https://api.github.com/repos/TestOwner/TestRepo"
        universal_config = UniversalConfig()
        self.project_config = BaseProjectConfig(universal_config)
        self.project_config.set_keychain(BaseProjectKeychain(self.project_config, None))
        self.repo_root = TemporaryDirectory()
        self.project_config.repo_info["root"] = pathlib.Path(self.repo_root.name)
        self.project_config.keychain.set_service(
            "github",
            ServiceConfig(
                {
                    "username": "TestUser",
                    "token": "TestPass",
                    "email": "testuser@testdomain.com",
                }
            ),
        )

    def tearDown(self):
        self.repo_root.cleanup()

    @responses.activate
    def test_resolve__default(self):
        responses.add(
            method=responses.GET,
            url=self.repo_api_url,
            json=self._get_expected_repo(owner="TestOwner", name="TestRepo"),
        )
        responses.add(
            "GET",
            "https://api.github.com/repos/TestOwner/TestRepo/releases/latest",
            json=self._get_expected_release("release/1.0"),
        )
        responses.add(
            "GET",
            "https://api.github.com/repos/TestOwner/TestRepo/git/refs/tags/release/1.0",
            json=self._get_expected_tag_ref("release/1.0", "tag_sha"),
        )

        source = GitHubSource(
            self.project_config, {"github": "https://github.com/TestOwner/TestRepo.git"}
        )
        assert (
            repr(source)
            == "<GitHubSource GitHub: TestOwner/TestRepo @ tags/release/1.0 (tag_sha)>"
        )

    @responses.activate
    def test_resolve__default_no_release(self):
        responses.add(
            method=responses.GET,
            url=self.repo_api_url,
            json=self._get_expected_repo(owner="TestOwner", name="TestRepo"),
        )
        responses.add(
            "GET",
            "https://api.github.com/repos/TestOwner/TestRepo/releases/latest",
            status=404,
        )
        responses.add(
            "GET",
            "https://api.github.com/repos/TestOwner/TestRepo/git/refs/heads/main",
            json=self._get_expected_ref("heads/main", "abcdef"),
        )

        source = GitHubSource(
            self.project_config, {"github": "https://github.com/TestOwner/TestRepo.git"}
        )
        assert (
            repr(source) == "<GitHubSource GitHub: TestOwner/TestRepo @ main (abcdef)>"
        )

    @responses.activate
    def test_resolve__commit(self):
        responses.add(
            method=responses.GET,
            url=self.repo_api_url,
            json=self._get_expected_repo(owner="TestOwner", name="TestRepo"),
        )

        source = GitHubSource(
            self.project_config,
            {"github": "https://github.com/TestOwner/TestRepo.git", "commit": "abcdef"},
        )
        assert repr(source) == "<GitHubSource GitHub: TestOwner/TestRepo @ abcdef>"

    @responses.activate
    def test_resolve__ref(self):
        responses.add(
            method=responses.GET,
            url=self.repo_api_url,
            json=self._get_expected_repo(owner="TestOwner", name="TestRepo"),
        )
        responses.add(
            "GET",
            "https://api.github.com/repos/TestOwner/TestRepo/git/refs/main",
            json=self._get_expected_ref("main", "abcdef"),
        )

        source = GitHubSource(
            self.project_config,
            {"github": "https://github.com/TestOwner/TestRepo.git", "ref": "main"},
        )
        assert (
            repr(source) == "<GitHubSource GitHub: TestOwner/TestRepo @ main (abcdef)>"
        )

    @responses.activate
    def test_resolve__branch(self):
        responses.add(
            method=responses.GET,
            url=self.repo_api_url,
            json=self._get_expected_repo(owner="TestOwner", name="TestRepo"),
        )
        responses.add(
            "GET",
            "https://api.github.com/repos/TestOwner/TestRepo/git/refs/heads/main",
            json=self._get_expected_ref("main", "abcdef"),
        )

        source = GitHubSource(
            self.project_config,
            {"github": "https://github.com/TestOwner/TestRepo.git", "branch": "main"},
        )
        assert (
            repr(source) == "<GitHubSource GitHub: TestOwner/TestRepo @ main (abcdef)>"
        )

    @responses.activate
    def test_resolve__tag(self):
        responses.add(
            method=responses.GET,
            url=self.repo_api_url,
            json=self._get_expected_repo(owner="TestOwner", name="TestRepo"),
        )