from __future__ import annotations

import logging
import re
from pathlib import Path

import pandas as pd

logger = logging.getLogger(__name__)

_INVALID_IDENT = re.compile(r"[^A-Za-z0-9_]")


def _sanitise_column(name: str) -> str:
    """Convert a raw column header to a valid HANA SQL identifier."""
    # Replace spaces / hyphens / dots with underscore
    clean = re.sub(r"[\s\-\.]", "_", str(name).strip())
    # Remove any remaining invalid characters
    clean = _INVALID_IDENT.sub("", clean)
    # Cannot start with a digit
    if clean and clean[0].isdigit():
        clean = "COL_" + clean
    # Fallback for empty names
    return clean or "UNNAMED"


def _sanitise_columns(df: pd.DataFrame) -> pd.DataFrame:
    """Apply _sanitise_column to every column header and deduplicate."""
    new_cols: list[str] = []
    seen: dict[str, int] = {}
    for col in df.columns:
        sanitised = _sanitise_column(col).upper()
        if sanitised in seen:
            seen[sanitised] += 1
            sanitised = f"{sanitised}_{seen[sanitised]}"
        else:
            seen[sanitised] = 0
        new_cols.append(sanitised)
    df.columns = new_cols  # type: ignore[assignment]
    return df




def read_file(
    path: str | Path,
    sheet_name: str | int = 0,
    encoding: str = "utf-8-sig",
) -> pd.DataFrame:

    p = Path(path)
    if not p.exists():
        raise FileNotFoundError(f"Data file not found: {p}")

    suffix = p.suffix.lower()
    logger.info("Reading %s file: %s", suffix, p)

    if suffix == ".csv":
        df = _read_csv(p, encoding)
    elif suffix in {".xlsx", ".xls"}:
        df = pd.read_excel(p, sheet_name=sheet_name, engine="openpyxl")
    elif suffix == ".json":
        df = pd.read_json(p, encoding=encoding)
    elif suffix == ".parquet":
        df = pd.read_parquet(p)
    else:
        raise ValueError(
            f"Unsupported file format '{suffix}'. "
            "Supported: .csv, .xlsx, .xls, .json, .parquet"
        )

    # Drop fully-empty columns / rows
    df.dropna(how="all", axis=1, inplace=True)
    df.dropna(how="all", axis=0, inplace=True)
    df.reset_index(drop=True, inplace=True)

    # Sanitise column names
    df = _sanitise_columns(df)

    logger.info("Loaded %d rows × %d columns.", len(df), len(df.columns))
    return df


def _read_csv(path: Path, encoding: str) -> pd.DataFrame:
    """Auto-detect CSV separator and read the file."""
    sample = path.read_bytes()[:4096].decode(encoding, errors="replace")
    sep = _sniff_separator(sample)
    logger.debug("Detected CSV separator: %r", sep)
    return pd.read_csv(path, sep=sep, encoding=encoding, low_memory=False)


def _sniff_separator(sample: str) -> str:
    """Return the most likely CSV separator for the given text sample."""
    candidates = {
        ",": sample.count(","),
        ";": sample.count(";"),
        "\t": sample.count("\t"),
        "|": sample.count("|"),
    }
    best = max(candidates, key=lambda k: candidates[k])
    # Fall back to comma if nothing stands out
    return best if candidates[best] > 0 else ","