from .base import PKStrategy
from infer_db.utils import logger
from infer_db.connectors import BaseConnector

class ExistingConstraintStrategy(PKStrategy):
    def detect(self, table_name: str, connector: BaseConnector):
        logger.info(f"Checking existing constraints for {table_name}")
        all_constraints = connector.get_existing_constraints()
        
        # Simple, clean filtering
        pks = [
            row['column_name'] 
            for row in all_constraints 
            if row['table_name'] == table_name and row['constraint_type'] == 'PRIMARY KEY'
        ]
        return pks

class SurrogateKeyStrategy(PKStrategy):
    """Checks if the column behaves like a numeric sequence."""
    def detect(self, table_name: str, connector: BaseConnector):
        cols = connector.get_columns_metadata(table_name)
        candidates = []
        
        for col in cols:
            # 1. Check by Definition (Serial/Identity)
            default = str(col.get('column_default') or '')
            if 'nextval' in default.lower():
                candidates.append(col['column'])
                continue # Move to next column
            
            # # 2. Type Check: Must be integer-like
            # if 'int' in col['dtype'].lower():
            #     stats = connector.get_column_stats(table_name, col['column'])
            #     # stats = (min, max, distinct_count)
            #     if stats and stats[2] > 0:
            #         min_val, max_val, count = stats
            #         # 2. Sequence Check: If it's a tight sequence
            #         if (max_val - min_val + 1) == count:
            #             candidates.append(col['column'])
        return candidates

class DataValidationStrategy(PKStrategy):
    def detect(self, table_name: str, connector: BaseConnector):
        # We fetch the metadata we added earlier (dtype and char_len)
        cols = connector.get_columns_metadata(table_name)
        valid_candidates = []
        
        # Configuration for "Sensible" PKs
        FORBIDDEN_TYPES = [
            'float', 'double', 'decimal', 'numeric', 'real',
            'bytea', 'json', 'jsonb', 'xml',
            'timestamp', 'time', 'interval' # <--- Block metadata columns
        ]
        MAX_VARCHAR_LENGTH = 200

        for col in cols:
            dtype = col['dtype'].lower()
            char_len = col.get('char_len')

            # Rule A: Block forbidden types
            if any(t in dtype for t in FORBIDDEN_TYPES):
                continue
            
            # Rule B: Handle "Text" and "UUID" explicitly
            # If it's a UUID type, we allow it (no length check needed usually)
            if 'uuid' in dtype:
                pass
            # If it is 'text' (unbounded) or a long varchar, reject it
            elif (char_len and char_len > MAX_VARCHAR_LENGTH):
                continue

            valid_candidates.append(col['column'])
            
        return valid_candidates
    
class UniquenessStrategy(PKStrategy):
    def detect(self, table_name: str, connector: BaseConnector):
        metadata = connector.get_columns_metadata(table_name)
        total_rows = connector.get_row_count(table_name)
        
        if total_rows == 0:
            return []

        unique_cols = []
        for col in metadata:
            # PKs must be NOT NULL, so we only check those to save time
            if col['is_nullable'] == 'NO':
                stats = connector.get_column_stats(table_name, col['column'])
                if stats:
                    distinct_count = stats[2]
                    # If every row has a different value, it's a unique candidate
                    if distinct_count == total_rows:
                        unique_cols.append(col['column'])
        
        return unique_cols