
import pytest
import unittest


def pytest_addoption(parser):
    """
    Add custom command-line options to pytest.
    """
    parser.addoption(
        "--run-skipped",
        action="store_true",
        default=False,
        help="Force run tests marked with @unittest.skip or @unittest.skipIf"
    )
    parser.addoption(
        "--only-skipped",
        action="store_true",
        default=False,
        help="Run ONLY tests that are marked as skipped (and force them to run)"
    )


def pytest_configure(config):
    """
    Override unittest.skip and unittest.skipIf decorators to force tests to run.
    This is called once before any test collection begins.
    """
    # Override if either flag is present
    if not (config.getoption("--run-skipped") or config.getoption("--only-skipped")):
        return
    
    # Store original skip decorators
    original_skip = unittest.skip
    original_skipIf = unittest.skipIf
    original_skipUnless = unittest.skipUnless
    
    # Create no-op decorator that just returns the function/class unchanged
    # BUT mark it so we can identify it was originally skipped
    def no_skip(reason):
        """Replace skip decorator - returns function/class but marks it as originally skipped"""
        def decorator(test_item):
            # Add marker to track that this was originally skipped
            if hasattr(test_item, '__dict__'):
                test_item._was_skipped = True
                test_item._skip_reason = reason
            return test_item
        return decorator
    
    def no_skipIf(condition, reason):
        """Replace skipIf decorator - marks if condition was True"""
        def decorator(test_item):
            # Add marker if condition would have caused skip
            if hasattr(test_item, '__dict__') and condition:
                test_item._was_skipped = True
                test_item._skip_reason = reason
            return test_item
        return decorator
    
    def no_skipUnless(condition, reason):
        """Replace skipUnless decorator - marks if condition was False"""
        def decorator(test_item):
            # Add marker if condition would have caused skip
            if hasattr(test_item, '__dict__') and not condition:
                test_item._was_skipped = True
                test_item._skip_reason = reason
            return test_item
        return decorator
    
    # Override unittest skip decorators globally
    unittest.skip = no_skip
    unittest.skipIf = no_skipIf
    unittest.skipUnless = no_skipUnless
    
    # Store originals in case we need to restore them
    config._original_skip = original_skip
    config._original_skipIf = original_skipIf
    config._original_skipUnless = original_skipUnless


def pytest_unconfigure(config):
    """
    Restore original skip decorators after tests complete.
    """
    if hasattr(config, '_original_skip'):
        unittest.skip = config._original_skip
        unittest.skipIf = config._original_skipIf
        unittest.skipUnless = config._original_skipUnless


@pytest.hookimpl(tryfirst=True)
def pytest_collection_modifyitems(config, items):
    """
    Remove skip markers from collected test items.
    This works for pytest.mark.skip as well as unittest skips on both functions and classes.
    """
    run_skipped = config.getoption("--run-skipped")
    only_skipped = config.getoption("--only-skipped")
    
    if not (run_skipped or only_skipped):
        return
    
    items_to_remove = []
    
    for item in items:
        # Check if item has skip markers (pytest style)
        has_skip_marker = any(marker.name in ('skip', 'skipif') for marker in item.own_markers)
        
        # Check if item was originally decorated with unittest.skip
        has_unittest_skip = False
        if hasattr(item, 'obj'):
            # Check the test method/function itself
            has_unittest_skip = getattr(item.obj, '_was_skipped', False)
            
            # Also check the class if this is a test method
            if not has_unittest_skip and hasattr(item, 'cls') and item.cls is not None:
                has_unittest_skip = getattr(item.cls, '_was_skipped', False)
        
        was_skipped = has_skip_marker or has_unittest_skip
        
        if only_skipped:
            # For --only-skipped: keep only tests that were skipped
            if not was_skipped:
                items_to_remove.append(item)
            else:
                # Remove skip markers so the test will run
                item.own_markers = [
                    marker for marker in item.own_markers 
                    if marker.name not in ('skip', 'skipif')
                ]
        else:
            # For --run-skipped: just remove skip markers from all tests
            item.own_markers = [
                marker for marker in item.own_markers 
                if marker.name not in ('skip', 'skipif')
            ]
    
    # Remove non-skipped tests when using --only-skipped
    if only_skipped:
        for item in items_to_remove:
            items.remove(item)
    