from abc import ABC, abstractmethod
from infer_db.connectors import BaseConnector

class PKStrategy(ABC):
    @abstractmethod
    def detect(self, table_name: str, connector: BaseConnector):
        """
        Logic to decide if columns are Primary Keys.
        Should return a list of potential PK column names.
        """
        pass

class FKStrategy(ABC):
    @abstractmethod
    def detect(self, source_table: str, target_table: str, source_cols: list, target_pks: dict, connector: BaseConnector, source_pks_list: list):
        pass

    def check_types_compatible(self, source_dtype: str, target_dtype: str):
        """
        Step 3 from Diagram: Eliminate distant data types.
        """
        s_type = source_dtype.lower()
        t_type = target_dtype.lower()
        
        # Define Type Groups
        numerics = ['int', 'serial', 'numeric', 'number', 'decimal', 'float', 'double', 'real']
        strings = ['char', 'text', 'string', 'varchar']
        dates = ['date', 'time', 'year']
        uuids = ['uuid']

        # 1. Exact Match is always good
        if s_type == t_type:
            return True
            
        # 2. Group Compatibility (Int vs Float, Varchar vs Text)
        if any(x in s_type for x in numerics) and any(x in t_type for x in numerics):
            return True
        if any(x in s_type for x in strings) and any(x in t_type for x in strings):
            return True

        # 3. Cross-Type "Castable" Compatibility (User's Request)
        # Allow Integer <-> String (e.g. ID "123" vs 123)
        # We rely on downstream validation (Jaccard) to catch false positives.
        if (any(x in s_type for x in numerics) and any(x in t_type for x in strings)) or \
           (any(x in s_type for x in strings) and any(x in t_type for x in numerics)):
            return True

        # 4. UUID <-> String (Common in modern apps)
        if (any(x in s_type for x in uuids) and any(x in t_type for x in strings)) or \
           (any(x in s_type for x in strings) and any(x in t_type for x in uuids)):
            return True

        return False