"""Test ModuleFinder."""

import os
import py_compile
import sys
from importlib.machinery import BYTECODE_SUFFIXES, SOURCE_SUFFIXES

import pytest
from generate_samples import (
    absolute_import_test,
    bytecode_test,
    coding_default_utf8_test,
    coding_explicit_cp1252_test,
    coding_explicit_utf8_test,
    create_package,
    extended_opargs_test,
    maybe_test,
    maybe_test_new,
    package_test,
    relative_import_test,
    relative_import_test_2,
    relative_import_test_3,
    relative_import_test_4,
    same_name_as_bad_test,
    sub_package_test,
)

from cx_Freeze import ConstantsModule, ModuleFinder

# Each test description is a list of 5 items:
#
# 1. a module name that will be imported by ModuleFinder
# 2. a list of module names that ModuleFinder is required to find
# 3. a list of module names that ModuleFinder should complain
#    about because they are not found
# 4. a list of module names that ModuleFinder should complain
#    about because they MAY be not found
# 5. a string specifying packages to create; the format is obvious imo.
#
# Each package will be created in test_dir, and test_dir will be
# removed after the tests again.
# ModuleFinder searches in a path that contains test_dir, plus
# the standard path search directory.


def _do_test(
    test_dir,
    import_this,
    modules,
    missing,  # noqa: ARG001
    maybe_missing,  # noqa: ARG001
    source,
    report=False,
    debug=0,  # noqa: ARG001
    modulefinder_class=ModuleFinder,
    **kwargs,
):
    create_package(test_dir, source)
    finder = modulefinder_class(
        ConstantsModule(),
        path=[test_dir, *sys.path],
        # debug=debug,
        **kwargs,
    )
    finder.modules = []  # remove default modules
    finder._modules = {}  # pylint: disable=protected-access
    finder.include_module(import_this)
    if report:
        finder.report_missing_modules()
    modules = sorted(set(modules))
    found = sorted([module.name for module in finder.modules])
    # check if we found what we expected, not more, not less
    assert found == modules

    # check for missing and maybe missing modules
    # bad, maybe = finder.any_missing_maybe()
    # self.assertEqual(bad, missing)
    # self.assertEqual(maybe, maybe_missing)


@pytest.mark.parametrize(
    ("import_this", "modules", "missing", "maybe_missing", "source"),
    [
        absolute_import_test,
        coding_default_utf8_test,
        coding_explicit_cp1252_test,
        coding_explicit_utf8_test,
        extended_opargs_test,
        maybe_test,
        maybe_test_new,
        package_test,
        relative_import_test,
        relative_import_test_2,
        relative_import_test_3,
        relative_import_test_4,
        same_name_as_bad_test,
        sub_package_test,
    ],
    ids=[
        "absolute_import_test",
        "coding_default_utf8_test",
        "coding_explicit_cp1252_test",
        "coding_explicit_utf8_test",
        "extended_opargs_test",
        "maybe_test",
        "maybe_test_new",
        "package_test",
        "relative_import_test",
        "relative_import_test_2",
        "relative_import_test_3",
        "relative_import_test_4",
        "same_name_as_bad_test",
        "sub_package_test",
    ],
)
def test_finder(
    tmp_path,
    import_this,
    modules,
    missing,
    maybe_missing,
    source,
):
    """Provides test cases for ModuleFinder class."""
    _do_test(tmp_path, import_this, modules, missing, maybe_missing, source)


def test_bytecode(tmp_path):
    """Provides bytecode test case for ModuleFinder class."""
    base_path = tmp_path / "a"
    source_path = base_path.with_suffix(SOURCE_SUFFIXES[0])
    bytecode_path = base_path.with_suffix(BYTECODE_SUFFIXES[0])
    with source_path.open("wb") as file:
        file.write(b"testing_modulefinder = True\n")
    py_compile.compile(os.fspath(source_path), cfile=os.fspath(bytecode_path))
    os.remove(source_path)
    _do_test(tmp_path, *bytecode_test)


def test_zip_include_packages(tmp_path):
    """Provides test cases for ModuleFinder class."""
    _do_test(
        tmp_path,
        *sub_package_test,
        zip_exclude_packages=["*"],
        zip_include_packages=["p"],
    )


def test_zip_exclude_packages(tmp_path):
    """Provides test cases for ModuleFinder class."""
    _do_test(
        tmp_path,
        *sub_package_test,
        zip_exclude_packages=["p"],
        zip_include_packages=["*"],
    )
