from .models import (
    License,
    Public,
    Findings,
    ClearingStatus,
    Action,
    Action1,
    Agent,
    ApiInfo,
    File,
    Folder,
    Group,
    Hash,
    HeathInfo,
    Info,
    Job,
    Kind,
    LicenseGetResponse,
    LicensePostRequest,
    LicenseShortnameGetResponse,
    LicenseShortnamePatchRequest,
    Public,
    ReportFormat1,
    ReportFormat2,
    ScanOptions,
    SearchResults,
    SearchType,
    SearchType1,
    SearchType2,
    Status5,
    TokenRequest,
    Upload,
    UploadLicense,
    UploadLicenses,
    UploadsPostRequest,
    UploadSummary,
    UploadType1,
    UploadType2,
    User,
    ReportFormat
)

import requests
import time
import configparser
import datetime
import sys
from pathlib import Path
from typing import List
from requests_toolbelt.multipart.encoder import MultipartEncoder


class easy_fossy:

    def __init__(self, config_file: str, server_to_use: str = "test"):
        self.config_file = config_file
        self.server = server_to_use
        # config_file = 'config.ini'
        if not Path(config_file).exists():
            print(
                f'config.ini file ->  {config_file} doesn\'t exist. Please run set_config_ini_file_full_path(config_file=\'full_path_to_config.ini\')')
            sys.exit(1)
        self.config_parser = configparser.ConfigParser()
        self.config_parser.read(config_file)

        self.config = self.config_parser[self.server]
        self.url = self.config.get('url')

        self.token_expire = self.config.get('token_expire')
        self.reports_location = self.config.get('reports_location')

        self.today = datetime.date.today()

        self.now = datetime.datetime.now()
        self.dt_format = "%d-%m-%Y %H:%M"
        # print(today)
        # print(now.strftime(dt_format))
        self.token_expire_yyyy_mm_dd = self.today + \
            datetime.timedelta(days=self.config.getint('token_valdity_days'))

        self.bearer_token = self.config.get('bearer_token')
        if self.token_expire:
            token_expire_datetime = datetime.date.fromisoformat(
                self.token_expire)
        else:
            token_expire_datetime = None
        self.group_name = self.config.get('group_name')

        def get_user_group(self):
            self.config['group_name'] = str(
                self.create_new_user_group(new_group_name='fossy'))
            print('No user group found, Creating a group_name called -> fossy')
            with open(self.config_file, 'w') as cf:
                self.config_parser.write(cf)
            return self.config.get('group_name')

        if not self.group_name:
            self.group_name = get_user_group()

        if(not self.bearer_token or not token_expire_datetime or (self.today > token_expire_datetime)):
            self.bearer_token = self.get_token_by_uname_pwd()
        else:
            print('Re using the existing unexpired Token')

    def set_config_ini_file_full_path(self, config_file: str):
        """ Sets config file. set_config_ini_file_full_path(config_file= full_path_to/config.ini)"""
        self.config_file = config_file

    def create_new_user_group(self, new_group_name: str) -> str:
        payload = ""
        headers = {
            "accept": "application/json",
            "name": new_group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "POST", self.url+str('groups'), data=payload, headers=headers)

        match response.json():
            case {**info}:
                report_info = Info(**info)
                print(f'{report_info.message}')
                return new_group_name
            case _:
                print(response.text)

    def get_token_by_uname_pwd(self) -> str:
        """Get the token via user name and password in the config"""
        payload = {
            "username": self.config.get('uname'),
            "password": self.config.get('pwd'),
            "token_name": str('created_viaapi_on_')+str(self.now.strftime(self.dt_format)),
            "token_scope": self.config.get('access'),
            "token_expire": str(self.token_expire_yyyy_mm_dd)
        }
        headers = {
            "accept": "application/json",
            "Content-Type": "application/json",
        }

        response = requests.request(
            "POST", self.url+str('tokens'), json=payload, headers=headers)

        match response.json():
            case {"Authorization": self.bearer_token}:
                self.config['bearer_token'] = self.bearer_token
                self.config['token_expire'] = str(self.token_expire_yyyy_mm_dd)
                with open(self.config_file, 'w') as cf:
                    self.config_parser.write(cf)
                self.bearer_token = self.config.get('bearer_token')
                if self.bearer_token != "":
                    print(
                        f'Added token to bearer_token param of your config {self.bearer_token}')
                return self.bearer_token
            case _:
                print('Error while getting token')
                print(response.text)
                sys.exit(1)

    def get_all_jobs(self) -> List[Job]:
        """List of jobs present in the given instance"""
        payload = ""
        headers = {
            "accept": "application/json",
            "limit": "1000",
            "page": "1",
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str('jobs'), data=payload, headers=headers)

        match response.json():
            case [*args]:
                jobs = []
                for job in args:
                    jobs.append(Job(**job))
                # for j in jobs:
                #     print(jobs)
                return jobs
            case _:
                print(response.text)

    # get_all_jobs(group_name)

    def get_job_info_by_id(self, job_id: int) -> Job:
        """give the job_id to get the
        {
        "id": 2,
        "name": "drawio-Source.zip",
        "queueDate": "2021-10-04 10:42:38.577655+00",
        "uploadId": "2",
        "userId": "3",
        "groupId": "3",
        "eta": 0,
        "status": "Completed"
        }
        """
        payload = ""
        headers = {
            "accept": "application/json",
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str(f'jobs/{job_id}'), data=payload, headers=headers)

        match response.json():
            case {**job}:
                job = Job(**job)
                print(job)
                return job
            case _:
                print(response.text)

    # get_job_info_by_id(job_id=3)

    def get_job_info_by_upload_id(self, upload_id: int) -> Job:
        """give the upload_id to get the job status
        {
        "id": 2,
        "name": "drawio-Source.zip",
        "queueDate": "2021-10-04 10:42:38.577655+00",
        "uploadId": "2",
        "userId": "3",
        "groupId": "3",
        "eta": 0,
        "status": "Completed"
        }
        """
        payload = ""
        headers = {
            "accept": "application/json",
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str(f'jobs?upload={upload_id}'), data=payload, headers=headers)

        match response.json():
            case {**job}:
                job = Job(**job)
                print(job)
                return job
            case _:
                print(response.text)

    # get_job_info_by_upload_id(job_id=3)

    def generate_and_get_desired_report_for_uploadid(self, upload_id: int, report_format: ReportFormat):
        """For given upload_id generate the report job to get report id and use to download desired Report Format

        class ReportFormat(Enum):
            dep5 = 'dep5'
            spdx2 = 'spdx2'
            spdx2tv = 'spdx2tv'
            readmeoss = 'readmeoss'
            unifiedreport = 'unifiedreport'
        """
        payload = ""
        headers = {
            "accept": "application/json",
            "uploadId": str(upload_id),
            "reportFormat": str(report_format.name),
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }
        report_info: Info = None
        report_id: int = None
        response = requests.request(
            "GET", self.url+str('report'), data=payload, headers=headers)

        match response.json():
            case {"message": url_with_report_id}:
                report_id = url_with_report_id.rsplit('/', 1).pop()
                print(report_id)

            case {**info}:
                report_info = Info(**info)
                print(report_info.message)
                # return report_info
            case _:
                print(response.text)

        payload = ""
        headers = {
            "accept": "text/plain",
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }
        timeout = 20
        timewait = 0.2
        timer = 0
        response = requests.request(
            "GET", self.url+str('report/')+str(report_id), data=payload, headers=headers)
        while response.status_code != 200:

            print(f'waiting for {timewait} sec')
            time.sleep(timewait)
            response = requests.request(
                "GET", self.url+str(f'report/{report_id}'), data=payload, headers=headers)
            if timer > timeout:
                break
            if response.status_code == 200:
                break

        # print(response.headers)
        file_name = response.headers.get(
            "Content-Disposition").split("filename=")[1]
        path_with_file = self.reports_location+str(file_name.replace('"', ''))

        if report_format != ReportFormat.unifiedreport:
            with open(path_with_file, 'w', encoding="utf-8") as f:
                f.write(response.text)
        else:
            with open(path_with_file, 'wb') as f:
                # 2 MB chunks
                for chunk in response.iter_content(1024 * 1024 * 2):
                    f.write(chunk)

    # generate_and_get_desired_report_for_uploadid(upload_id=3, report_format=ReportFormat.unifiedreport)

    def get_all_folders(self) -> List[Folder]:
        """ Get all the folders in given fossy instance"""
        payload = ""
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str('folders'), data=payload, headers=headers)

        match response.json():
            case [*args]:
                folders = []
                for folder in args:
                    folders.append(Folder(**folder))
                for f in folders:
                    print(f)
                # print(folders)
                return folders
            case _:
                print(response.text)

    # get_all_folders()

    def get_folder_info_by_id(self, folder_id: int) -> Folder:
        """get_folder_info_by_id(folder_id: int) -> Folder"""
        payload = ""
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str('folders/')+str(folder_id), data=payload, headers=headers)

        match response.json():
            case {**args}:
                folder = Folder(**args)
                print(folder)
                return folder
            case _:
                print(response.text)

    # get_folder_info_by_id(folder_id=11)

    def change_folder_name_or_desc(self, folder_id: int, new_folder_name: str = '', new_folder_desc: str = ''):
        """name and desc are optional, mandatory input is the folder id"""
        payload = ""
        headers = {
            "accept": "application/json",
            "name": new_folder_name,
            "description": new_folder_desc,
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "PATCH", self.url+str(f'folders/{folder_id}'), data=payload, headers=headers)
        match response.json():
            case {**info}:
                report_info = Info(**info)
                print(report_info.message)
                return report_info
            case _:
                print(response.text)

    # change_folder_name_or_desc(folder_id=3, new_folder_name='', new_folder_desc='')

    # change_folder_name_or_desc(folder_id=2, new_folder_name='', new_folder_desc = 'scans triggered from sw360 test')
    # get_all_folders()

    def create_folder_under_parent_folder_id(self, parent_folder_id: int, folder_name: str) -> Info:
        """create the folder under parent folder id with given folder_name"""
        payload = ""
        headers = {
            "accept": "application/json",
            "parentFolder": str(parent_folder_id),
            "folderName": folder_name,
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "POST", self.url+str('folders'), data=payload, headers=headers)

        match response.json():
            case {**info}:
                report_info = Info(**info)
                print(f'Created folder id is {report_info.message}')
                return report_info
            case _:
                print(response.text)

    # create_folder_under_parent_folder_id(
    #     parent_folder_id=1, folder_name='test')
    # create_folder_under_parent_folder_id(
    #     parent_folder_id=6, folder_name='submove')
    # get_all_folders()

    def delete_folder_by_id(self, folder_id: int):
        """delete_folder_by_id(folder_id: int)"""
        payload = ""
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "DELETE", self.url+str('folders/{folder_id}'), data=payload, headers=headers)

        match response.json():
            case {**info}:
                report_info = Info(**info)
                print(f'Deleted folder is {report_info.message}')
                # return report_info
            case _:
                print(response.text)

    # delete_folder_by_id(folder_id=3)
    # get_all_folders()

    def apply_action_to_folderid(self, actions: Action, folder_id: int, parent_folder_id: int) -> Info:
        """apply_action_to_folderid(actions: Action, folder_id: int, parent_folder_id: int) -> Info"""
        payload = ""
        headers = {
            "accept": "application/json",
            "parent": str(parent_folder_id),
            "action": actions.name,
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "PUT", self.url+str('folders/{folder_id}'), data=payload, headers=headers)

        match response.json():
            case {**info}:
                report_info = Info(**info)
                print(f'{report_info.message}')
                return report_info
            case _:
                print(response.text)

    # apply_action_to_folderid(actions=Action.copy, folder_id=5, parent_folder_id=2)
    # apply_action_to_folderid(actions=Action.move, folder_id=6, parent_folder_id=2)

    # change_folder_name_or_desc(folder_id=11, new_folder_name='',
    #                            new_folder_desc='scans triggered from sw360 test')

    # get_all_folders('fossy')

    def get_upload_summary_for_uploadid(self, upload_id: int) -> UploadSummary:
        """get upload summary for given upload_id
        {
        "id": 2,
        "uploadName": "drawio-Source.zip",
        "assignee": null,
        "mainLicense": null,
        "uniqueLicenses": 29,
        "totalLicenses": 842,
        "uniqueConcludedLicenses": 0,
        "totalConcludedLicenses": 0,
        "filesToBeCleared": 933,
        "filesCleared": 933,
        "clearingStatus": "Open",
        "copyrightCount": 1359
        }
        """
        payload = ""
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str(f'uploads/{upload_id}/summary'), data=payload, headers=headers)
        match response.json():
            case {**info}:
                upload_summary = UploadSummary(**info)
                print(
                    f'Returned upload summary for file {upload_summary.uploadName}')
                return upload_summary
            case _:
                print(response.text)

    # get_upload_summary_for_uploadid(upload_id=2)

    def get_all_uploads_based_on(self, folder_id: int, is_recursive: bool, search_pattern_key: str, upload_status: ClearingStatus, assignee: str, since_yyyy_mm_dd: str, page: int, limit: int) -> List[Upload]:
        """get_all_uploads_based_on(folder_id: int, is_recursive: bool, search_pattern_key: str, upload_status: ClearingStatus, assignee: str, since_yyyy_mm_dd: str, page: int, limit: int) -> List[Upload]"""
        querystring = {"folderId": folder_id, "recursive": is_recursive, "name": search_pattern_key,
                       "status": upload_status.name, "assignee": assignee, "since": since_yyyy_mm_dd}

        payload = ""
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "page": str(page),
            "limit": str(limit),
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str('uploads'), data=payload, headers=headers, params=querystring)

        match response.json():
            case [*args]:
                uploads = []
                for upload in args:
                    uploads.append(Upload(**upload))
                # for upload in uploads:
                #     print(upload)
                return uploads
            case _:
                print(response.text)

    # get_all_uploads_based_on(folder_id=1, is_recursive=True,
    #                          search_pattern_key='', upload_status=ClearingStatus.Open, assignee='', since_yyyy_mm_dd='', page=1, limit=1000)

    def get_licenses_found_by_agents_for_uploadid(self, upload_id: int, agents: List[str], show_directories: bool) -> UploadLicenses | Info:
        """get licenses acc to agent
        class Agent(Enum):
            nomos = 'nomos'
            monk = 'monk'
            ninka = 'ninka'
            ojo = 'ojo'
            reportImport = 'reportImport'
            reso = 'reso'
        """
        querystring = {"agent": agents, "containers": str(show_directories)}
        payload = ""
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str(f'uploads/{upload_id}/licenses'), data=payload, headers=headers, params=querystring)

        match response.json():
            case [*args]:
                UploadLicenses = []
                for uploadLicense in args:
                    UploadLicenses.append(UploadLicense(**uploadLicense))
                for f in UploadLicenses:
                    print(f)
                # print(folders)
                return UploadLicenses
            case {**info}:
                report_info = Info(**info)
                print(f'{report_info.message}')
                return report_info
            case _:
                print(response.text)

    # get_licenses_found_by_agents_for_uploadid(upload_id=2, show_directories=True, group_name=group_name, agents=[
    #                                           Agent.ninka.name, Agent.monk.name, Agent.nomos.name, Agent.ojo.name, Agent.reportImport.name, Agent.reso.name])

    def get_upload_id_by_local_package_upload(self, file_path: str, folder_id: int, upload_desc: str, visibility: Public) -> str:
        """get_upload_id_by_local_package_upload(file_path: str, folder_id: int, upload_desc: str, visibility: Public) -> str"""
        # files = {'file': open(file_path, 'rb')}

        if Path(file_path).exists():
            print(f'File path {file_path} exists')

        file_name = file_path.split('/').pop()
        print(file_name)
        m = MultipartEncoder([('fileInput', (file_name, open(
            file_path, 'rb'), 'application/octet-stream'))],
            None, encoding='utf-8')
        headers = {
            # "accept": "application/json",
            "folderId": str(folder_id),
            "groupName": self.group_name,
            "uploadDescription": upload_desc,
            "public": visibility.name,
            "Content-Type": m.content_type,
            "Authorization": self.bearer_token
        }
        response = requests.post(
            self.url+str('uploads'), data=m, headers=headers)

        timeout = 20
        timewait = 0.2
        timer = 0

        while response.status_code != 201:

            print(f'waiting for {timewait} sec')
            time.sleep(timewait)
            response = requests.post(
                self.url+str('uploads'), data=m, headers=headers)
            timer = timer+timewait
            if timer > timeout:
                break
            if response.status_code == 201:
                break

        match response.json():
            case {**info}:
                report_info = Info(**info)
                print(f'upload id is {report_info.message}')
                return report_info.message
            case _:
                print(response.text)

    # get_upload_id_by_local_package_upload(
    #     file_path='uploads/commons-io-2.11.0-src.zip', folder_id=1, upload_desc='commons-io-2.11.0', visibility=Public.public)

    def check_url_exists(url: str):
        """
        Checks if a url exists
        :param url: url to check
        :return: True if the url exists, false otherwise.
        """
        return requests.head(url, allow_redirects=True).status_code == 200

    def get_upload_id_by_download_url_package_upload(self, file_download_url: str, file_name: str, folder_id: int, upload_desc: str, visibility: Public) -> str:
        """get_upload_id_by_download_url_package_upload(file_download_url: str, file_name: str, folder_id: int, upload_desc: str, visibility: Public) -> str"""
        # files = {'file': open(file_path, 'rb')}
        if not self.check_url_exists(file_download_url):
            print(f'git url {file_download_url} is malformed')

        m = MultipartEncoder(
            fields={'url': file_download_url, 'name': file_name})
        headers = {
            # "accept": "application/json",
            "folderId": str(folder_id),
            "groupName": self.group_name,
            "uploadType": 'url',
            "uploadDescription": upload_desc,
            "public": visibility.name,
            "Content-Type": m.content_type,
            "Authorization": self.bearer_token
        }
        response = requests.post(
            self.url+str('uploads'), data=m, headers=headers)

        timeout = 20
        timewait = 0.2
        timer = 0

        while response.status_code != 201:

            print(f'waiting for {timewait} sec')
            time.sleep(timewait)
            response = requests.post(
                self.url+str('uploads'), data=m, headers=headers)
            # print(response.text)
            timer = timer+timewait
            if timer > timeout:
                break
            if response.status_code == 201:
                break

        match response.json():
            case {**info}:
                report_info = Info(**info)
                print(f'upload id is {report_info.message}')
                return report_info.message
            case _:
                print(response.text)

    # get_upload_id_by_download_url_package_upload(
    #     file_download_url='https://github.com/dineshr93/pageres/archive/refs/heads/master.zip', file_name='pageres', folder_id=1, upload_desc='commons-io-2.11.0', visibility=Public.public)

    def get_upload_id_by_giturl_package_upload(self, git_url: str, branch_name: str, upload_name: str, folder_id: int, upload_desc: str, visibility: Public) -> str:
        """get_upload_id_by_giturl_package_upload(git_url: str, branch_name: str, upload_name: str, folder_id: int, upload_desc: str, visibility: Public) -> str"""
        # files = {'file': open(file_path, 'rb')}

        if not self.check_url_exists(git_url):
            print(f'git url {git_url} is malformed')

        file_name = git_url.split('/').pop()
        print(file_name)

        payload = {
            "vcsType": "git",
            "vcsUrl": git_url,
            "vcsBranch": branch_name,
            "vcsName": upload_name
        }
        headers = {
            # "accept": "application/json",
            "folderId": str(folder_id),
            "uploadDescription": upload_desc,
            "public": visibility.name,
            "ignoreScm": 'true',
            'uploadType': 'vcs',
            "groupName": self.group_name,
            # "Content-Type": "application/json",
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "POST", self.url+str('uploads'), json=payload, headers=headers)

        # print(response.status_code)
        # print(response.text)

        timeout = 20
        timewait = 0.2
        timer = 0

        while response.status_code != 201:

            print(f'waiting for {timewait} sec')
            time.sleep(timewait)
            response = requests.request(
                "POST", self.url+str('uploads'), json=payload, headers=headers)
            print(response.json())
            timer = timer + timewait
            if timer > timeout:
                break
            if response.status_code == 201:
                break

        match response.json():
            case {**info}:
                report_info = Info(**info)
                print(f'upload id is {report_info.message}')
                return report_info.message
            case _:
                print(response.text)

    # get_upload_id_by_giturl_package_upload(git_url='https://github.com/dineshr93/pageres', branch_name='master', upload_name='',
    #                                        folder_id=1, upload_desc='', visibility=Public.public)

    def trigger_analysis_for_upload_id(self, upload_id: int, folder_id: int) -> Info:
        """trigger_analysis_for_upload_id(upload_id: int, folder_id: int) -> Info"""
        payload = {
            "analysis": {
                "bucket": True,
                "copyright_email_author": True,
                "ecc": True,
                "keyword": True,
                "mime": True,
                "monk": True,
                "nomos": True,
                "ojo": True,
                "package": True,
                "reso": True
            },
            "decider": {
                "nomos_monk": True,
                "bulk_reused": True,
                "new_scanner": True,
                "ojo_decider": True
            },
            "reuse": {
                "reuse_upload": 0,
                "reuse_group": "string",
                "reuse_main": True,
                "reuse_enhanced": True,
                "reuse_report": True,
                "reuse_copyright": True
            }
        }
        headers = {
            "accept": "application/json",
            "folderId": str(folder_id),
            "uploadId": upload_id,
            "groupName": self.group_name,
            "Content-Type": "application/json",
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "POST", self.url+str('jobs'), json=payload, headers=headers)
        timeout = 50
        timewait = 0.5
        timer = 0
        while response.status_code != 201:
            print(f'waiting for {timewait} sec')
            time.sleep(timewait)
            response = requests.request(
                "POST", self.url+str('jobs'), json=payload, headers=headers)
            print(response.text)
            timer = timer + timewait
            if timer > timeout:
                break
            if response.status_code == 201:
                break
        match response.json():
            case {**info}:
                report_info = Info(**info)
                print(f'job id is {report_info.message}')
                return report_info
            case _:
                print(response.text)

    # trigger_analysis_for_upload_id(
    #     upload_id=4, folder_id=1, group_name=group_name)

    def trigger_analysis_for_upload_package(self, file_path: str, folder_id: int):
        """trigger_analysis_for_upload_package(file_path: str, folder_id: int)"""
        if not Path(file_path).exists():
            print(f'File path {file_path} doesn\'t exist')

        uploads: List[Upload] = self.get_all_uploads_based_on(folder_id=folder_id, is_recursive=True,
                                                              search_pattern_key='', upload_status=ClearingStatus.Open, assignee='', since_yyyy_mm_dd='', page=1, limit=1000, group_name=self.group_name)
        file_name = file_path.split('/').pop()

        upload_id = [u.id for u in uploads if file_name == u.uploadname]
        size = len(upload_id)
        is_present_uploadID = False
        if size > 1:
            is_present_uploadID = True
            print(f'{size} no of duplicates are there with ids {upload_id}')
            print('exiting.. please comeback after deleting duplicates via delete_uploads_by_upload_id(upload_id=upload_id, group_name=group_name)')
            sys.exit(1)
        elif size == 1:
            is_present_uploadID = True
            upload_id = upload_id[0]
        else:
            # no upload_id is there
            upload_id = self.get_upload_id_by_local_package_upload(
                file_path=file_path, folder_id=folder_id, upload_desc=file_name, visibility=Public.protected, group_name=group_name)

        if is_present_uploadID:
            jobs: List[Job] = [
                j for j in self.get_all_jobs(self.group_name) if j.uploadId == upload_id]

            if len(jobs) >= 1:
                print(f'Multiple jobs exists for same upload_id: {upload_id}')
                job = jobs.pop()
                print(f' Returning Existing Job ID :{job.id}')
                return job.id
        else:
            info = self.trigger_analysis_for_upload_id(
                upload_id=upload_id, folder_id=folder_id, group_name=self.group_name)
            print(f'Computed new Job ID is :{info.message}')
            return info.message

    # trigger_analysis_for_upload_package(
    #     file_path='uploads/commons-lang3-3.12.0-src.zip', folder_id=1, group_name=group_name)

    def trigger_analysis_for_url_upload_package(self, file_download_url: str, file_name: str, branch_name: str, folder_id: int):
        """trigger_analysis_for_url_upload_package(file_download_url: str, file_name: str, branch_name: str, folder_id: int)"""
        if not self.check_url_exists(file_download_url):
            print(f'git url {file_download_url} is malformed')

        uploads: List[Upload] = self.get_all_uploads_based_on(folder_id=folder_id, is_recursive=True,
                                                              search_pattern_key='', upload_status=ClearingStatus.Open, assignee='', since_yyyy_mm_dd='', page=1, limit=1000, group_name=self.group_name)

        upload_id = [u.id for u in uploads if file_name == u.uploadname]
        size = len(upload_id)
        is_present_uploadID = False
        if size > 1:
            is_present_uploadID = True
            print(f'{size} no of duplicates are there with ids {upload_id}')
            print('exiting.. please comeback after deleting duplicates via delete_uploads_by_upload_id(upload_id=upload_id, group_name=group_name)')
            sys.exit(1)
        elif size == 1:
            is_present_uploadID = True
            upload_id = upload_id[0]
        else:
            # no upload_id is there
            upload_id = self.get_upload_id_by_download_url_package_upload(
                file_download_url=file_download_url, file_name=file_name, folder_id=1, upload_desc=file_name, visibility=Public.public, group_name=group_name)

        if is_present_uploadID:
            jobs: List[Job] = [
                j for j in self.get_all_jobs(self.group_name) if j.uploadId == upload_id]

            if len(jobs) >= 1:
                print(f'Multiple jobs exists for same upload_id: {upload_id}')
                job = jobs.pop()
                print(f' Returning Existing Job ID :{job.id}')
                return job.id
        else:
            info = self.trigger_analysis_for_upload_id(
                upload_id=upload_id, folder_id=folder_id, group_name=group_name)
            print(f'Computed new Job ID is :{info.message}')
            return info.message

    # trigger_analysis_for_url_upload_package(
    #     file_download_url='https://github.com/dineshr93/pageres/archive/refs/heads/master.zip', file_name='pageres.zip', branch_name='', folder_id=1)

    def trigger_analysis_for_git_upload_package(self, git_url: str, branch_name: str, folder_id: int):
        """trigger_analysis_for_git_upload_package(git_url: str, branch_name: str, folder_id: int)"""
        if not self.check_url_exists(git_url):
            print(f'git url {git_url} is malformed')

        file_name = git_url.split('/').pop()
        print(file_name)

        uploads: List[Upload] = self.get_all_uploads_based_on(folder_id=folder_id, is_recursive=True,
                                                              search_pattern_key='', upload_status=ClearingStatus.Open, assignee='', since_yyyy_mm_dd='', page=1, limit=1000, group_name=self.group_name)

        upload_id = [u.id for u in uploads if file_name == u.uploadname]
        size = len(upload_id)
        is_present_uploadID = False
        if size > 1:
            is_present_uploadID = True
            print(f'{size} no of duplicates are there with ids {upload_id}')
            print('exiting.. please comeback after deleting duplicates via delete_uploads_by_upload_id(upload_id=upload_id, group_name=group_name)')
            sys.exit(1)
        elif size == 1:
            is_present_uploadID = True
            upload_id = upload_id[0]
        else:
            # no upload_id is there
            upload_id = self.get_upload_id_by_giturl_package_upload(git_url=git_url, branch_name=branch_name, upload_name=file_name,
                                                                    folder_id=1, upload_desc='', visibility=Public.public, group_name=self.group_name)

        if is_present_uploadID:
            jobs: List[Job] = [
                j for j in self.get_all_jobs(self.group_name) if j.uploadId == upload_id]

            if len(jobs) >= 1:
                print(f'Multiple jobs exists for same upload_id: {upload_id}')
                job = jobs.pop()
                print(f' Returning Existing Job ID :{job.id}')
                return job.id
        else:
            info = self.trigger_analysis_for_upload_id(
                upload_id=upload_id, folder_id=folder_id, group_name=self.group_name)
            print(f'Computed new Job ID is :{info.message}')
            return info.message

    # trigger_analysis_for_git_upload_package(
    #     git_url='https://github.com/dineshr93/pageres', branch_name='master', folder_id=1)

    def delete_uploads_by_upload_id(self, upload_id: int) -> Info:
        """Delete the upload by given upload id"""
        payload = ""
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "DELETE", self.url+str(f'uploads/{upload_id}'), data=payload, headers=headers)

        match response.json():
            case {**info}:
                report_info = Info(**info)
                print(f'{report_info.message}')
                return report_info
            case _:
                print(response.text)

    # delete_uploads_by_upload_id(upload_id=7, group_name=group_name)

    def get_all_license_based_on(self, is_active: str, license_kind: Kind, page: int, limit: int) -> List[License]:
        """
        get_all_license_based_on(is_active: str, license_kind: Kind, limit: int) -> List[License]

        is_active must be true or false

        class Kind(Enum):
        candidate = 'candidate'
        main = 'main'
        all = 'all'
        """
        querystring = {"kind": license_kind.name}

        payload = ""
        headers = {
            "accept": "application/json",
            "page": str(page),
            "limit": str(limit),
            "active":  is_active.lower(),
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str('license'), data=payload, headers=headers, params=querystring)

        match response.json():
            case [*args]:
                licenses = []
                for license in args:
                    licenses.append(License(**license))
                # for lic in licenses:
                #     print('======')
                #     print(lic)
                return licenses
            case {**info}:
                report_info = Info(**info)
                print(f'{report_info.message}')
                return report_info
            case _:
                print(response.text)

    # get_all_license_based_on(
    #     is_active='true', license_kind=Kind.main, page=1, limit=1)

    def get_all_license_short_names_based_on(self, is_active: str, license_kind: Kind, page: int, contains_key: str, limit: int) -> List[str]:
        """
        get_all_license_short_names_based_on(is_active: str, license_kind: Kind, page: int, contains_key: str, limit: int) -> List[str]

        use contains_key to filter based on keywords.

        is_active must be true or false

        class Kind(Enum):
        candidate = 'candidate'
        main = 'main'
        all = 'all'
        """
        licenses = self.get_all_license_based_on(
            is_active=is_active, license_kind=license_kind, page=page, limit=limit, group_name=self.group_name)
        license_shortnames = [
            license.shortName for license in licenses if contains_key.lower() in license.shortName.lower()]
        if len(license_shortnames) > 0:
            return license_shortnames
        else:
            print('No License shortnames been found')
            return None

    # sns = get_all_license_short_names_based_on(
    #     is_active='true', license_kind=Kind.main, contains_key='gp', page=1, limit=10000)
    # for i, sn in enumerate(sns, start=1):
    #     print(f'{i}. {sn}')

    def get_license_by_short_name(self, short_name: str) -> LicenseShortnameGetResponse:
        """
        get_license_by_short_name(short_name: str) -> LicenseShortnameGetResponse
        {
        "id": 317,
        "shortName": "GPL",
        "fullName": "GNU General Public License",
        "text": "GPL is referenced without a version number. Please look up GPL in the License Admin to view the different versions.",
        "url": "",
        "risk": null,
        "isCandidate": false,
        "obligations": []
        }
        """
        payload = ""
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str(f'license/{short_name}'), data=payload, headers=headers)
        match response.json():
            case {**license_info} if response.status_code == 200:
                license_info = LicenseShortnameGetResponse(**license_info)
                print(f'{license_info}')
                return license_info
            case {**info} if response.status_code == 404:
                report_info = Info(**info)
                print(f'{report_info}')
                sys.exit(1)
            case _:
                print(response.text)
                sys.exit(1)

    # get_license_by_short_name(short_name='AGPL-1.0')

    def update_license_info_by_short_name(self, short_name: str, new_full_name: str, new_license_text: str, new_url: str, new_risk: int) -> Info:
        """update information about a specific license by shortname"""

        payload = {
            "fullName": new_full_name,
            "text": new_license_text,
            "url": new_url,
            "risk": new_risk
        }
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "Content-Type": "application/json",
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "PATCH", self.url+str(f'license/{short_name}'), json=payload, headers=headers)

        match response.json():
            case {**info} if response.status_code == 200:
                report_info = Info(**info)
                print(f'{report_info}')
                return report_info
            case _:
                print(response.text)

    # update_license_info_by_short_name(short_name='', new_full_name='', new_license_text='', new_url='', new_risk=2)

    def add_new_license(self, unique_short_name: str, new_full_name: str, new_license_text: str, new_url: str, new_risk: int, isCandidate: bool, merge_request: bool) -> Info:
        """add_new_license(unique_short_name: str, new_full_name: str, new_license_text: str, new_url: str, new_risk: int, isCandidate: bool, merge_request: bool):"""
        payload = {
            "shortName": unique_short_name,
            "fullName": new_full_name,
            "text": new_license_text,
            "url": new_url,
            "risk": new_risk,
            "isCandidate": isCandidate,
            "mergeRequest": merge_request
        }
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "Content-Type": "application/json",
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "POST", self.url, json=payload, headers=headers)

        match response.json():
            case {**info} if response.status_code == 200:
                report_info = Info(**info)
                print(f'{report_info}')
                return report_info
            case {**info} if response.status_code == 409:
                report_info = Info(**info)
                print(f'{report_info}')
                return report_info
            case _:
                print(response.text)

    # add_new_license(unique_short_name='', new_full_name='', new_license_text='',
    #                 new_url='', new_risk=2, isCandidate=True, merge_request=False)

    def search_files_based_on(self, filename_wildcard: str, searchType: SearchType, uploadId: int, tag: str, filesizemin_bytes: int, filesizemax_bytes: int, license: str, copyright: str) -> List[SearchResults] | Info:
        """Most are optional parameters
        def search_files_based_on(self, filename_wildcard: str, searchType: SearchType, uploadId: int, tag: str, filesizemin_bytes: int, filesizemax_bytes: int, license: str, copyright: str) -> List[SearchResults] | Info:
        """
        payload = ""
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "searchType": searchType.name,
            "uploadId": uploadId,
            "filename": filename_wildcard,
            "tag": tag,
            "filesizemin": filesizemin_bytes,
            "filesizemax": filesizemax_bytes,
            "license": license,
            "copyright": copyright,
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "GET", self.url+str('search'), data=payload, headers=headers)

        match response.json():
            case [*args]:
                search_results = []
                for search_result in args:
                    search_results.append(SearchResults(**search_result))
                for s in search_results:
                    print(s)
                # print(folders)
                return search_results
            case {**info}:
                report_info = Info(**info)
                print(f'{report_info.message}')
                return report_info
            case _:
                print(response.text)

    def get_file_by_any_one_of_sha1_or_md5_or_sha256(self, sha1: str = '', md5: str = '', sha256: str = '') -> List[File]:
        """def get_file_by_any_one_of_sha1_or_md5_or_sha256(self, sha1: str = '', md5: str = '', sha256: str = '') -> List[File]"""
        json_params = ''
        if sha1 != '':
            json_params = str(f'"sha1": {sha1}')
        else:
            json_params = ''
        if md5 != '':
            json_params = str(f'"md5": {md5}')
        else:
            json_params = ''
        if sha256 != '':
            json_params = str(f'"sha256": {sha256}')
        else:
            json_params = ''

        if json_params == '':
            print('Please provide any_one_of_sha1_or_md5_or_sha256 values')
            sys.exit(1)
        payload = [
            {
                json_params
            }
        ]
        headers = {
            "accept": "application/json",
            "groupName": self.group_name,
            "Content-Type": "application/json",
            "Authorization": self.bearer_token
        }

        response = requests.request(
            "POST", self.url+str('filesearch'), json=payload, headers=headers)

        match response.json():
            case [*args]:
                files = []
                for file in args:
                    files.append(File(**file))
                for f in files:
                    print(f)
                # print(folders)
                return files
            case _:
                print(response.text)
