"""
automl_lib.detector
~~~~~~~~~~~~~~~~~~~
Auto-detect data type (tabular, image, text, audio, timeseries) and
ML task (classification, regression, forecasting).
"""

from __future__ import annotations

import os
from pathlib import Path

import pandas as pd

from .utils import get_logger, list_files, file_extension

logger = get_logger(__name__)

# ── File-extension groups ────────────────────────────────────────────────
IMAGE_EXTS = {"jpg", "jpeg", "png", "bmp", "gif", "tiff", "webp"}
AUDIO_EXTS = {"wav", "mp3", "flac", "ogg", "m4a"}
VIDEO_EXTS = {"mp4", "avi", "mov", "mkv", "webm"}
TABULAR_EXTS = {"csv", "tsv", "xlsx", "xls", "parquet", "json", "feather"}
TEXT_EXTS = {"txt", "jsonl"}


def detect_data_type(path: str) -> str:
    """Infer the predominant data modality at *path*.

    Returns one of: ``"tabular"``, ``"image"``, ``"text"``,
    ``"audio"``, ``"video"``, ``"timeseries"``.
    """
    p = Path(path)

    # Single file → use extension
    if p.is_file():
        ext = file_extension(path)
        if ext in TABULAR_EXTS:
            return _tabular_or_timeseries(path)
        if ext in IMAGE_EXTS:
            return "image"
        if ext in AUDIO_EXTS:
            return "audio"
        if ext in VIDEO_EXTS:
            return "video"
        if ext in TEXT_EXTS:
            return "text"
        # Fallback: try to read as tabular
        return "tabular"

    # Directory → majority vote on child file extensions
    if p.is_dir():
        counts: dict[str, int] = {
            "image": 0, "audio": 0, "video": 0,
            "tabular": 0, "text": 0,
        }
        for fp in list_files(path):
            ext = file_extension(fp)
            if ext in IMAGE_EXTS:
                counts["image"] += 1
            elif ext in AUDIO_EXTS:
                counts["audio"] += 1
            elif ext in VIDEO_EXTS:
                counts["video"] += 1
            elif ext in TABULAR_EXTS:
                counts["tabular"] += 1
            elif ext in TEXT_EXTS:
                counts["text"] += 1

        best = max(counts, key=lambda k: counts[k])
        if counts[best] == 0:
            # Check for sub-directories (image-folder convention)
            subdirs = [d for d in os.listdir(path)
                       if os.path.isdir(os.path.join(path, d))]
            if subdirs:
                # Check first sub-dir for images
                sample_dir = os.path.join(path, subdirs[0])
                sample_files = list_files(sample_dir, list(IMAGE_EXTS))
                if sample_files:
                    best = "image"
        logger.info(f"Detected data type: {best} (file counts: {counts})")
        return best

    raise FileNotFoundError(f"Path does not exist: {path}")


def _tabular_or_timeseries(path: str) -> str:
    """Peek at a tabular file to decide if it looks like time-series."""
    try:
        df = pd.read_csv(path, nrows=50)
    except Exception:
        return "tabular"

    # Heuristic: if there is a datetime column and data is sorted by it
    for col in df.columns:
        try:
            parsed = pd.to_datetime(df[col], infer_datetime_format=True)
            if parsed.is_monotonic_increasing or parsed.is_monotonic_decreasing:
                logger.info(f"Column '{col}' looks like a datetime index → timeseries")
                return "timeseries"
        except Exception:
            continue
    return "tabular"


def detect_task(
    data: pd.DataFrame | None = None,
    data_type: str = "tabular",
    target_column: str | None = None,
    num_classes: int | None = None,
) -> str:
    """Infer the ML task type.

    Returns one of: ``"classification"``, ``"regression"``,
    ``"forecasting"``.
    """
    if data_type == "timeseries":
        return "forecasting"

    if data_type in ("image", "audio", "video"):
        # Default to classification; can be overridden
        return "classification"

    if data_type == "text":
        return "classification"

    # Tabular: inspect target column dtype
    if data is not None and target_column and target_column in data.columns:
        target = data[target_column]
        nunique = target.nunique()
        if num_classes is not None:
            return "classification"
        if target.dtype.kind in ("O", "b"):  # object / bool
            return "classification"
        if nunique <= 20 and nunique / len(target) < 0.05:
            logger.info(
                f"Target '{target_column}' has {nunique} unique values "
                "→ classification"
            )
            return "classification"
        return "regression"

    return "classification"  # safe default
