import requests
from tqdm import tqdm


def retrieve_detected_apk(request_url="https://api.koodous.com/apks?search=detected%3Atrue",
                          nb_apk_min=50):
    """
    Crawl through Koodous apk list to retrieve detected apk
    :return: A list of detected apk from the list of apk of koodous
    :rtype: list of DetectedApk
    """

    detected_apk_list = []
    progress_bar = tqdm(total=nb_apk_min, unit="apk", ncols=100)
    progress_bar.set_description(desc="Crawling through Koodous")

    def recursive_crawling(url, package_set=None):
        if package_set is None:
            package_set = {}

        r = requests.get(url=url)
        if len(detected_apk_list) > nb_apk_min:
            return detected_apk_list

        elif r.status_code is 200:
            r_json = r.json()
            r_json_detected = list(filter(lambda x: x['detected'], r_json['results']))
            detected_apks = [DetectedApk(app=apk['app'], package_name=apk['package_name'],
                                         sha256=apk['sha256'], detected=apk['detected'])
                             for apk in r_json_detected]

            # set cast to remove duplicates package that have different hash
            new_detected_apks = list(set(filter(lambda x: x.package_name not in package_set, detected_apks)))
            new_detected_packages = set(map(lambda x: x.package_name, new_detected_apks))

            if package_set:
                package_set.update(new_detected_packages)
            else:
                package_set = new_detected_packages

            detected_apk_list.extend(new_detected_apks)
            progress_bar.update(len(new_detected_apks))

            if r_json['next']:
                return recursive_crawling(url=r_json['next'], package_set=package_set)
            else:
                return detected_apk_list

        else:
            print('request to {} not valid'.format(request_url))
            return detected_apk_list

    recursive_crawling(url=request_url)
    progress_bar.close()
    return detected_apk_list


class DetectedApk:
    """
    Detected Apk information (small version)
    """

    def __init__(self, detected, sha256, app, package_name):
        self.detected = detected
        self.sha256 = sha256
        self.app = app
        self.package_name = package_name

    def __str__(self):
        return '{}: (package_name: {}, sha256: {}, detected: {})'\
            .format(self.app, self.package_name, self.sha256, self.detected)

    def __repr__(self):
        return '\n' + self.__str__()

    def __eq__(self, other):
        return id(self) != id(other)

    def __hash__(self):
        return hash(self.package_name)
