"""Shared utilities for view_history and related tools.

Consolidates duplicated helper functions: affected-file normalization,
project-name detection, and timestamp formatting.
"""

import subprocess
from datetime import datetime
from pathlib import Path
from typing import Optional, Union


def normalize_affected_files(affected_files: list) -> list[str]:
    """Normalize affected_files to a list of file-path strings.

    Handles three input shapes:
      - plain strings
      - dicts with ``file_path`` or ``path`` key
      - other types (converted via ``str()``)
    """
    if not affected_files:
        return []

    result: list[str] = []
    for item in affected_files:
        if isinstance(item, str):
            result.append(item)
        elif isinstance(item, dict):
            file_path = item.get("file_path", item.get("path", ""))
            if file_path:
                result.append(file_path)
        else:
            result.append(str(item))
    return result


def get_project_name(project_root: Union[str, Path, None]) -> Optional[str]:
    """Get a project name from a root path.

    Tries to resolve the git repository name first, then falls back to
    the directory basename. Returns ``None`` when *project_root* is falsy.
    """
    if not project_root:
        return None

    root = Path(project_root)

    try:
        result = subprocess.run(
            ["git", "-C", str(root), "rev-parse", "--show-toplevel"],
            capture_output=True,
            text=True,
            timeout=2,
        )
        if result.returncode == 0:
            return Path(result.stdout.strip()).name
    except (subprocess.TimeoutExpired, FileNotFoundError):
        pass

    return root.name


def format_timestamp(timestamp: str, style: str = "full") -> str:
    """Format an ISO-8601 timestamp string.

    Args:
        timestamp: An ISO-8601 timestamp (e.g. ``2026-01-29T14:30:45.123``).
        style: One of:
            - ``"full"``  -> ``"2026-01-29 14:30:45"``
            - ``"time"``  -> ``"14:30:45"``
            - ``"short"`` -> ``"Jan 29"``
            - ``"date"``  -> ``"Jan 29, 2026"``

    Returns:
        Formatted string, or the original *timestamp* on parse failure.
    """
    if not timestamp:
        return "Unknown"

    try:
        # Normalise trailing "Z" so fromisoformat can parse it
        ts = timestamp.replace("Z", "+00:00")
        dt = datetime.fromisoformat(ts)
    except (ValueError, TypeError):
        # Fall back to manual splitting for non-standard formats
        return _format_timestamp_fallback(timestamp, style)

    if style == "time":
        return dt.strftime("%H:%M:%S")
    if style == "short":
        return dt.strftime("%b %-d")
    if style == "date":
        return dt.strftime("%b %d, %Y")
    # default: "full"
    return dt.strftime("%Y-%m-%d %H:%M:%S")


def _format_timestamp_fallback(timestamp: str, style: str) -> str:
    """Best-effort formatting when ``datetime.fromisoformat`` fails."""
    try:
        if style == "time":
            if "T" in timestamp:
                time_part = timestamp.split("T")[1]
                return time_part.split(".")[0]
            return timestamp

        if style in ("short", "date"):
            date_part = timestamp.split("T")[0] if "T" in timestamp else timestamp.split(" ")[0]
            parts = date_part.split("-")
            if len(parts) == 3:
                months = [
                    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
                ]
                month_idx = int(parts[1]) - 1
                if 0 <= month_idx < 12:
                    if style == "short":
                        return f"{months[month_idx]} {int(parts[2])}"
                    return f"{months[month_idx]} {int(parts[2]):02d}, {parts[0]}"
            return date_part

        # full
        if "T" in timestamp:
            date_part, time_part = timestamp.split("T")
            time_part = time_part.split(".")[0]
            return f"{date_part} {time_part}"
        return timestamp
    except Exception:
        return timestamp
