from pgsql_parser import Column
from sqlalchemy import (
    ARRAY,
    BLOB,
    JSON,
    TIMESTAMP,
    UUID,
    BigInteger,
    Boolean,
    Date,
    DateTime,
    Float,
    Integer,
    Interval,
    LargeBinary,
    Numeric,
    SmallInteger,
    String,
    Text,
    Time,
)
from sqlalchemy.dialects import mssql, mysql, oracle, postgresql, sqlite


class DatabaseTypeConverter:
    def __init__(self):
        # Mapping SQLAlchemy type string names to database type string names
        # Values can be direct strings or lambda functions for dynamic sizing
        self._db_type_mapping = {
            "postgresql": {
                "integer": "Integer",
                "int": "Integer",
                "bigint": "BigInteger",
                "smallint": "SmallInteger",
                "character varying": "String",
                "varchar": "String",
                "text": "Text",
                "boolean": "Boolean",
                "bool": "Boolean",
                "date": "Date",
                "timestamp without time zone": "DateTime",
                "timestamp": "DateTime",
                "timestamp with time zone": "TIMESTAMP",
                "timestamptz": "TIMESTAMP",
                "time without time zone": "Time",
                "time": "Time",
                "time with time zone": "Time",
                "timetz": "Time",
                "real": "Float",
                "float4": "Float",
                "double precision": "Float",
                "float8": "Float",
                "numeric": "Numeric",
                "decimal": "Numeric",
                "bytea": "LargeBinary",
                "json": "JSON",
                "jsonb": "JSON",
                "uuid": "UUID",
                "interval": "INTERVAL",
            },
            "mssql": {
                "int": "Integer",
                "bigint": "BigInteger",
                "smallint": "SmallInteger",
                "tinyint": "SmallInteger",
                "varchar": "String",
                "nvarchar": "String",
                "char": "String",
                "nchar": "String",
                "text": "Text",
                "ntext": "Text",
                "bit": "Boolean",
                "date": "Date",
                "datetime": "DateTime",
                "datetime2": "DateTime",
                "smalldatetime": "DateTime",
                "time": "Time",
                "float": "Float",
                "real": "Float",
                "decimal": "Numeric",
                "numeric": "Numeric",
                "varbinary": "LargeBinary",
                "binary": "LargeBinary",
                "image": "LargeBinary",
                "timestamp": "LargeBinary",
                "uniqueidentifier": "UUID",
                "json": "JSON",
            },
            "sqlite": {
                "integer": "Integer",
                "int": "Integer",
                "bigint": "BigInteger",
                "int8": "BigInteger",
                "smallint": "SmallInteger",
                "int2": "SmallInteger",
                "text": "Text",
                "varchar": "Text",
                "char": "Text",
                "clob": "Text",
                "boolean": "Boolean",
                "bool": "Boolean",
                "date": "Date",
                "datetime": "DateTime",
                "time": "Time",
                "real": "Float",
                "double": "Float",
                "float": "Float",
                "numeric": "Numeric",
                "decimal": "Numeric",
                "blob": "BLOB",
            },
            "mysql": {
                "int": "Integer",
                "integer": "Integer",
                "bigint": "BigInteger",
                "smallint": "SmallInteger",
                "tinyint": "Boolean",
                "varchar": "String",
                "char": "String",
                "text": "Text",
                "tinytext": "Text",
                "mediumtext": "Text",
                "longtext": "Text",
                "boolean": "Boolean",
                "bool": "Boolean",
                "date": "Date",
                "datetime": "DateTime",
                "timestamp": "TIMESTAMP",
                "time": "Time",
                "float": "Float",
                "double": "Float",
                "decimal": "Numeric",
                "numeric": "Numeric",
                "binary": "LargeBinary",
                "varbinary": "LargeBinary",
                "tinyblob": "BLOB",
                "blob": "BLOB",
                "mediumblob": "BLOB",
                "longblob": "BLOB",
                "json": "JSON",
            },
            "oracle": {
                "number": "Numeric",
                "integer": "Integer",
                "int": "Integer",
                "smallint": "SmallInteger",
                "varchar2": "String",
                "nvarchar2": "String",
                "char": "String",
                "nchar": "String",
                "long": "Text",
                "clob": "Text",
                "nclob": "Text",
                "date": "Date",
                "timestamp": "TIMESTAMP",
                "timestamp with time zone": "TIMESTAMP",
                "timestamp with local time zone": "TIMESTAMP",
                "interval year to month": "INTERVAL",
                "interval day to second": "INTERVAL",
                "float": "Float",
                "binary_float": "Float",
                "binary_double": "Float",
                "raw": "LargeBinary",
                "long raw": "LargeBinary",
                "blob": "BLOB",
                "bfile": "BLOB",
                "json": "JSON",
            },
        }

    def _get_sqlalchemy_type(self, column: Column, dialect_name: str) -> str:
        """
        Maps a SQLAlchemy Column type to its string representation for a given database dialect,
        using string names for SQLAlchemy types in the mapping.

        Args:
            column: The SQLAlchemy Column object.
            dialect_name: The name of the database dialect (e.g., 'postgresql', 'mysql', 'mssql', 'oracle', 'sqlite').

        Returns:
            A string representing the database-specific type.
        """
        db_types = self._db_type_mapping.get(dialect_name.lower(), {})
        sqlalchemy_type = str(column.data_type).lower()
        return str(column.type).upper()
