from __future__ import annotations

import logging
import re
from pathlib import Path
from typing import NamedTuple

import pandas as pd

logger = logging.getLogger(__name__)


_MAX_NVARCHAR = 5000
_MIN_NVARCHAR = 64


class ColumnDef(NamedTuple):
    name: str        
    hana_type: str   



def _dtype_to_hana(series: pd.Series) -> str:
    """Return the HANA SQL type string for a single pandas Series."""
    dtype = series.dtype

    if pd.api.types.is_bool_dtype(dtype):
        return "BOOLEAN"

    if pd.api.types.is_integer_dtype(dtype):
        # Use BIGINT for int64 to avoid overflow
        return "BIGINT" if dtype == "int64" else "INTEGER"

    if pd.api.types.is_float_dtype(dtype):
        return "REAL" if dtype == "float32" else "DOUBLE"

    if pd.api.types.is_datetime64_any_dtype(dtype):
        return "TIMESTAMP"

    if pd.api.types.is_timedelta64_dtype(dtype):
        # Store as total seconds (BIGINT)
        return "BIGINT"

    if hasattr(dtype, "categories"):          # CategoricalDtype
        return "NVARCHAR(255)"

    # Everything else → treat as string; measure actual max length
    max_len = int(series.dropna().astype(str).str.len().max() or 1)
    max_len = max(max_len + 10, _MIN_NVARCHAR)   # a bit of headroom
    max_len = min(max_len, _MAX_NVARCHAR)
    return f"NVARCHAR({max_len})"



def derive_names(file_path: str | Path) -> tuple[str, str]:
    stem = Path(file_path).stem
    clean = re.sub(r"[\s\-\.]", "_", stem)
    clean = re.sub(r"[^A-Za-z0-9_]", "", clean).upper()
    if not clean or clean[0].isdigit():
        clean = "DATA_" + clean

    schema_name = "HF_" + clean
    table_name  = clean
    return schema_name, table_name


def build_column_defs(df: pd.DataFrame) -> list[ColumnDef]:
    """Return a ColumnDef for every column in *df*."""
    return [ColumnDef(name=col, hana_type=_dtype_to_hana(df[col])) for col in df.columns]


def create_schema_sql(schema_name: str) -> str:
    return f'CREATE SCHEMA "{schema_name}"'


def create_table_sql(schema_name: str, table_name: str, col_defs: list[ColumnDef]) -> str:
    col_lines = ",\n    ".join(f'"{c.name}" {c.hana_type}' for c in col_defs)
    return (
        f'CREATE COLUMN TABLE "{schema_name}"."{table_name}" (\n'
        f"    {col_lines}\n"
        f")"
    )