# Copyright (c) 2021-2023 Cisco Systems, Inc. and its affiliates
# All rights reserved.

import requests
import testtools

from soufi import exceptions
from soufi.finder import SourceType
from soufi.finders import java
from soufi.testing import base


class TestJavaFinder(base.TestCase):
    def make_finder(self, name=None, version=None):
        if name is None:
            name = self.factory.make_string('name')
        if version is None:
            version = self.factory.make_string('version')
        return java.JavaFinder(name, version, SourceType.java)

    def test_get_source_url(self):
        finder = self.make_finder()
        group = self.factory.make_string()
        url = self.factory.make_url()
        data = dict(response=dict(docs=[dict(g=group)]))

        get = self.patch_get_with_response(requests.codes.ok, json=data)
        head = self.patch_head_with_response(requests.codes.ok)
        head.return_value.url = url
        found_url = finder.get_source_url()
        self.assertEqual(found_url, url)
        expected = dict(
            q=f'a:{finder.name} v:{finder.version} l:sources', rows=1
        )
        get.assert_called_once_with(
            java.MAVEN_SEARCH_URL, params=expected, timeout=finder.timeout
        )
        expected = dict(
            filepath=f'{group}/{finder.name}/{finder.version}/'
            f'{finder.name}-{finder.version}-sources.jar'
        )
        head.assert_called_once_with(
            java.MAVEN_REPO_URL,
            params=expected,
            allow_redirects=True,
            timeout=finder.timeout,
        )

    def test_get_source_info_raises_when_get_response_fails(self):
        self.patch_get_with_response(requests.codes.bad)
        finder = self.make_finder()
        with testtools.ExpectedException(exceptions.SourceNotFound):
            finder.get_source_url()

    def test_get_source_info_raises_when_head_response_fails(self):
        group = self.factory.make_string()
        data = dict(response=dict(docs=[dict(g=group)]))
        self.patch_get_with_response(requests.codes.ok, json=data)
        self.patch_head_with_response(requests.codes.not_found)
        finder = self.make_finder()
        with testtools.ExpectedException(exceptions.SourceNotFound):
            finder.get_source_url()

    def test_get_source_info_raises_when_head_response_times_out(self):
        group = self.factory.make_string()
        data = dict(response=dict(docs=[dict(g=group)]))
        self.patch_get_with_response(requests.codes.ok, json=data)
        head = self.patch(requests, 'head')
        head.side_effect = requests.exceptions.Timeout
        finder = self.make_finder()
        with testtools.ExpectedException(exceptions.SourceNotFound):
            finder.get_source_url()

    def test_find(self):
        url = self.factory.make_url()
        finder = self.make_finder()
        self.patch(finder, 'get_source_url').return_value = url

        disc_source = finder.find()
        self.assertIsInstance(disc_source, java.JavaDiscoveredSource)
        self.assertEqual([url], disc_source.urls)

    def test_get_release_history(self):
        finder = self.make_finder(name=self.factory.make_string())
        data = {
            'response': {
                'docs': [
                    {'v': '2.0.0', 'timestamp': 2000},
                    {'v': '1.0.0', 'timestamp': 1000},
                ]
            }
        }
        self.patch_get_with_response(requests.codes.ok, json=data)

        history = finder.get_release_history()
        self.assertEqual(
            ['1.0.0', '2.0.0'], [item['version'] for item in history]
        )

    def test_get_release_history_sorts_none_timestamp_as_oldest(self):
        finder = self.make_finder(name=self.factory.make_string())
        data = {
            'response': {
                'docs': [
                    {'v': '4.0.2'},
                    {'v': '5.1.0.RELEASE', 'timestamp': 1514764800000},
                ]
            }
        }
        self.patch_get_with_response(requests.codes.ok, json=data)

        history = finder.get_release_history()
        self.assertEqual(
            ['4.0.2', '5.1.0.RELEASE'],
            [item['version'] for item in history],
        )

    def test_get_release_history_raises_when_request_fails(self):
        finder = self.make_finder(name=self.factory.make_string())
        self.patch_get_with_response(requests.codes.bad_request)
        self.assertRaises(
            exceptions.SourceNotFound,
            finder.get_release_history,
        )

    def test_get_release_history_raises_when_docs_filtered(self):
        finder = self.make_finder(name=self.factory.make_string())
        data = {
            'response': {
                'docs': [
                    {'v': ''},
                    {'v': ''},
                ]
            }
        }
        self.patch_get_with_response(requests.codes.ok, json=data)
        self.assertRaises(
            exceptions.SourceNotFound,
            finder.get_release_history,
        )

    def test_get_release_history_uses_group_id(self):
        name = self.factory.make_string()
        group_id = self.factory.make_string()
        finder = java.JavaFinder(
            name,
            self.factory.make_string(),
            SourceType.java,
            group_id=group_id,
        )
        data = {'response': {'docs': [{'v': '1.0.0', 'timestamp': 1000}]}}
        get = self.patch_get_with_response(requests.codes.ok, json=data)

        finder.get_release_history()
        call_args = get.call_args
        query = call_args.kwargs['params']['q']
        self.assertIn(f'g:{group_id}', query)
        self.assertIn(f'a:{name}', query)


class TestNPMDiscoveredSource(base.TestCase):
    def make_discovered_source(self, url=None):
        if url is None:
            url = self.factory.make_url()
        return java.JavaDiscoveredSource([url])

    def test_repr(self):
        url = self.factory.make_url()
        jds = self.make_discovered_source(url)
        self.assertEqual(url, repr(jds))

    def test_make_archive(self):
        jds = self.make_discovered_source()
        self.assertEqual(jds.make_archive, jds.remote_url_is_archive)
