import pytest
from infer_db.connectors.factory import ConnectorFactory
from infer_db.pipeline import InferenceEngine
from infer_db.strategies.pk_strategies import ExistingConstraintStrategy, SurrogateKeyStrategy, UniquenessStrategy, DataValidationStrategy
import infer_db.config as config

@pytest.fixture(scope="module")
def engine():
    # DOUBLE CHECK these match your docker-compose.yml exactly
    db_config = {
        "host": config.DB_HOST,
        "dbname": config.DB_NAME,
        "user": config.DB_USER,
        "password": config.DB_PASSWORD,
        "port": config.DB_PORT
    }
    db = ConnectorFactory.create_connector("postgres", db_config)
    
    eng = InferenceEngine(db)
    eng.add_pk_strategy(ExistingConstraintStrategy())
    eng.add_pk_strategy(SurrogateKeyStrategy())
    eng.add_pk_strategy(UniquenessStrategy())
    # We assume DataValidationStrategy is used inside the engine.run() logic as a filter
    return eng

# --- PART 1: Standard Table Tests (From before) ---

def test_surrogate_detection(engine):
    # 'users.id' should be detected as a surrogate (SERIAL)
    report = engine.run()
    pk_info = report['users']['pks']
    
    assert 'id' in pk_info
    assert pk_info['id']['is_surrogate'] is True

def test_natural_key_detection(engine):
    # 'post_categories' uses composite keys that are NOT surrogates
    report = engine.run()
    pk_info = report['post_categories']['pks']
    
    assert 'post_id' in pk_info
    assert pk_info['post_id']['is_surrogate'] is False

def test_uniqueness_logic(engine):
    # 'users.username' is UNIQUE, so it should be detected as a candidate PK
    report = engine.run()
    pk_info = report['users']['pks']
    assert 'username' in pk_info 

# --- PART 2: Comprehensive Edge Case Tests (New) ---

def test_reject_null_columns(engine):
    """Test that a unique column is rejected if it contains NULLs."""
    report = engine.run()
    pks = report['edge_cases']['pks']
    
    # 'nullable_unique_col' has distinct values but one NULL -> Must fail
    assert 'nullable_unique_col' not in pks

def test_reject_duplicates(engine):
    """Test that a Not Null column is rejected if it has duplicates."""
    report = engine.run()
    pks = report['edge_cases']['pks']
    
    # 'duplicated_col' is NOT NULL but has 'dup_val' twice -> Must fail
    assert 'duplicated_col' not in pks

def test_detect_valid_alternates(engine):
    """Test that a column meeting all criteria (Unique + Not Null) is detected."""
    report = engine.run()
    pks = report['edge_cases']['pks']
    
    # 'valid_candidate' is perfect (Unique + Not Null) -> Should be found
    # 'id' is the official PK -> Should be found
    assert 'valid_candidate' in pks
    assert 'id' in pks

def test_surrogate_tagging(engine):
    """Ensure the engine correctly tags 'id' as surrogate and 'valid_candidate' as not."""
    report = engine.run()
    pks = report['edge_cases']['pks']
    
    assert pks['id']['is_surrogate'] is True
    assert pks['valid_candidate']['is_surrogate'] is False