import concurrent.futures
import logging
import os
import ssl
import sys
from urllib.request import urlopen

import pytest

import py7zr

# hack only for the test, it is highly discouraged for production.
ssl._create_default_https_context = ssl._create_unverified_context
testdata_path = os.path.join(os.path.dirname(__file__), 'data')
archives = [('qt3d.7z',
             'https://ftp.jaist.ac.jp/pub/qtproject/online/qtsdkrepository/'
             'windows_x86/desktop/qt5_5126/qt.qt5.5126.win64_mingw73/'
             '5.12.6-0-201911111120qt3d-Windows-Windows_10-Mingw73-Windows-Windows_10-X86_64.7z'),
            ('qtxmlpatterns.7z',
             'https://ftp1.nluug.nl/languages/qt/online/qtsdkrepository/'
             'windows_x86/desktop/qt5_5132/qt.qt5.5132.win64_mingw73/'
             '5.13.2-0-201910281254qtxmlpatterns-Windows-Windows_10-Mingw73-Windows-Windows_10-X86_64.7z'),
            ('qtactiveqt.7z',
             'http://mirrors.dotsrc.org/qtproject/online/qtsdkrepository/'
             'windows_x86/desktop/qt5_5132/qt.qt5.5132.win64_mingw73/'
             '5.13.2-0-201910281254qtactiveqt-Windows-Windows_10-Mingw73-Windows-Windows_10-X86_64.7z'),
            ('qtbase.7z',
             'http://qt.mirrors.tds.net/qt/online/qtsdkrepository/'
             'windows_x86/desktop/qt5_5132/qt.qt5.5132.win32_mingw73/'
             '5.13.2-0-201910281254qtbase-Windows-Windows_7-Mingw73-Windows-Windows_7-X86.7z'),
            ('opengl32sw.7z',
             'http://mirrors.ocf.berkeley.edu/qt/online/qtsdkrepository/windows_x86/desktop/'
             'qt5_5132/qt.qt5.5132.win64_mingw73/'
             '5.13.2-0-201910281254opengl32sw-64-mesa_12_0_rc2.7z'),
            ('EnvVarUpdate.7z', 'https://nsis.sourceforge.io/'
                                'mediawiki/images/a/ad/EnvVarUpdate.7z'),
            ('GTKVICE-3.3.7z', 'https://downloads.sourceforge.net/project/'
                               'vice-emu/releases/binaries/windows/GTK3VICE-3.4-win64.7z'),
            ('lpng1634.7z', 'https://github.com/glennrp/libpng-releases/raw/master/lpng1634.7z')
            ]


@pytest.mark.timeout(360)
@pytest.mark.remote_data
def test_concurrent_futures(tmp_path):

    def download_and_extract(ar, path):
        archive = path.joinpath(ar[0])
        try:
            resp = urlopen(ar[1])
            with open(archive, 'wb') as fd:
                while True:
                    chunk = resp.read(8196)
                    if not chunk:
                        break
                    fd.write(chunk)
            szf = py7zr.SevenZipFile(archive)
            szf.extractall(path=path)
            szf.close()
        except Exception:
            exc = sys.exc_info()
            logging.error("Caught error: %s" % exc[1])
            return False
        return True

    with concurrent.futures.ThreadPoolExecutor() as texec:
        tasks = [texec.submit(download_and_extract, ar, tmp_path) for ar in archives]
        for task in concurrent.futures.as_completed(tasks):
            if not task.result():
                raise Exception("Failed to extract.")


@pytest.mark.timeout(180)
def test_concurrent_extraction(tmp_path, caplog):

    def extractor(archive, path):
        szf = py7zr.SevenZipFile(archive, 'r')
        szf.extractall(path=path)
        szf.close()

    archives = ['bugzilla_4.7z', 'bzip2.7z', 'bzip2_2.7z', 'copy.7z',
                'empty.7z', 'github_14.7z', 'lzma2bcj.7z', 'mblock_1.7z',
                'mblock_3.7z', 'solid.7z', 'symlink.7z', 'test_1.7z', 'test_2.7z',
                'test_3.7z', 'test_5.7z', 'test_6.7z',
                'test_folder.7z', 'umlaut-non_solid.7z', 'umlaut-solid.7z', 'zerosize.7z']
    with concurrent.futures.ThreadPoolExecutor() as executor:
        tasks = [executor.submit(extractor, os.path.join(testdata_path, ar), tmp_path.joinpath(ar)) for ar in archives]
        done, not_done = concurrent.futures.wait(tasks, return_when=concurrent.futures.ALL_COMPLETED)
        if len(not_done) > 0:
            raise Exception("Extraction error.")
