from tests.conftest import *
from typing import Any, List
import pathlib
import subprocess
import sys
import pytest

@pytest.mark.parametrize("description,content,expected", [
    ("Basic requirements", "# This is a comment\n package-NE==1.13.0\n package-SW>=4.17.0,<=7.23.0\n package_NW\n analyzeAudio@git+https://github.com/hunterhogan/analyzeAudio.git ", [ 'analyzeAudio@git+https://github.com/hunterhogan/analyzeAudio.git', 'package-NE==1.13.0', 'package-SW>=4.17.0,<=7.23.0', 'package_NW' ] ),
    ("Invalid requirements", "invalid==requirement==1.0\nvalid-package==1.13.0", ['valid-package==1.13.0'] ),
    ("Multiple valid packages", "package-FR==11.0\npackage-JP==13.0", ['package-FR==11.0', 'package-JP==13.0'] ),
    ("Empty file", "", []),
    ("Comments only", "# Comment 1\n# Comment 2", []),
    ("Whitespace only", "    \n\t\n", []),
    ]
    , ids=lambda x: x if isinstance(x, str) else ""
)
def test_makeListRequirementsFromRequirementsFile(description, content, expected: List[str], pathTmpTesting: pathlib.Path):
    """Test requirements file parsing with various inputs."""
    pathRequirementsFile = pathTmpTesting / "requirements.txt"
    pathRequirementsFile.write_text(content)
    standardizedEqualTo(expected, makeListRequirementsFromRequirementsFile, pathRequirementsFile)

@pytest.mark.parametrize("description,paths,expected", [
    ("Multiple files with unique entries", [ ('requirements1.txt', 'package-NE==11.0\npackage-NW==13.0'), ('requirements2.txt', 'package-SW==17.0\npackage-SE==19.0') ], ['package-NE==11.0', 'package-NW==13.0', 'package-SE==19.0', 'package-SW==17.0'] ),
    ("Multiple files with duplicates", [ ('requirements1.txt', 'package-FR==11.0\npackage-common==13.0'), ('requirements2.txt', 'package-JP==17.0\npackage-common==13.0') ], ['package-FR==11.0', 'package-JP==17.0', 'package-common==13.0'] ),
])
def test_multiple_requirements_files(description, paths, expected, pathTmpTesting: pathlib.Path):
    """Test processing multiple requirements files."""
    pathFilenames = []
    for filename, content in paths:
        pathFile = pathTmpTesting / filename
        pathFile.write_text(content)
        pathFilenames.append(pathFile)

    standardizedEqualTo(expected, makeListRequirementsFromRequirementsFile, *pathFilenames)

def test_nonexistent_requirements_file(pathTmpTesting: pathlib.Path):
    """Test handling of non-existent requirements file."""
    pathFilenameNonexistent = pathTmpTesting / 'nonexistent.txt'
    standardizedEqualTo([], makeListRequirementsFromRequirementsFile, pathFilenameNonexistent)

@pytest.mark.parametrize("description,relativePathPackage,listRequirements,expected_contains", [
    ("Basic setup", 'package-NE', ['numpy>=11.0', 'pandas>=13.0'], [ "name='package-NE'", "packages=find_packages(where=r'package-NE')", "package_dir={'': r'package-NE'}", "install_requires=['numpy>=11.0', 'pandas>=13.0']", "include_package_data=True" ] ),
    ("Empty requirements", 'package-SW', [], [ "name='package-SW'", "install_requires=[]" ] ),
])
def test_make_setupDOTpy(description, relativePathPackage, listRequirements, expected_contains):
    """Test setup.py content generation."""
    setup_content = make_setupDOTpy(relativePathPackage, listRequirements)
    for expected in expected_contains:
        assert expected in setup_content

@pytest.mark.usefixtures("mockTemporaryFiles")
def test_installPackageTarget(mocker, pathTmpTesting: pathlib.Path):
    """Test package installation process."""
    # Setup test package structure
    pathPackageDir = pathTmpTesting / 'test-package-NE'
    pathPackageDir.mkdir()
    (pathPackageDir / 'requirements.txt').write_text('numpy>=11.0\npandas>=13.0')
    (pathPackageDir / '__init__.py').write_text('')
    (pathPackageDir / 'module_prime.py').write_text('print("Prime module")')

    # Mock subprocess.Popen
    mock_process = mocker.MagicMock()
    mock_process.stdout = ["Installing test-package-NE...\n"]
    mock_process.wait.return_value = 0
    mocker.patch('subprocess.Popen', return_value=mock_process)

    installPackageTarget(pathPackageDir)

    # Verify Popen was called correctly
    subprocess.Popen.assert_called_once() # type: ignore
    call_args = subprocess.Popen.call_args[1]['args'] # type: ignore
    assert call_args[0] == sys.executable
    assert call_args[1:4] == ['-m', 'pip', 'install']

# @pytest.mark.parametrize("description,argv,expected", [
#     ("No arguments", ['script.py'], 1),
#     ("Nonexistent path", ['script.py', '/path/to/nowhere'], 1),
#     ("Invalid directory", ['script.py', '/dev/null'], 1),
# ])
# def test_CLI_error_cases(description, argv, expected, mocker):
#     """Test CLI argument handling for error cases."""
#     mocker.patch('sys.argv', argv)
#     mocker.patch('pathlib.Path.exists', return_value=False)
#     mocker.patch('pathlib.Path.is_dir', return_value=False)
#     standardizedEqualTo(expected, standardizedSystemExit, expected, everyone_knows_what___main___is)

def test_main_function_chain(mocker):
    """Test the main function call chain."""
    mock_readability = mocker.patch('Z0Z_tools.pipAnything.readability_counts')
    main()
    mock_readability.assert_called_once()
