"""Config file load/save and path resolution."""

from __future__ import annotations

import json
import os
from datetime import datetime, timezone
from pathlib import Path
from typing import Any

# Accepted config field values
ACCEPTED_DATE_FORMATS = {"human", "iso"}
ACCEPTED_DISTANCE_UNITS = {"km", "mi"}

# Defaults
DEFAULT_DATE_FORMAT = "human"
DEFAULT_DISTANCE_UNIT = "km"

DEFAULT_CONFIG_PATH = Path.home() / ".config" / "tyta" / "config.json"


def get_config_path(override: str | None = None) -> Path:
    """Resolve config file path.

    Precedence: override argument > TOYOTA_CONFIG_FILE env var > default.

    Args:
        override: Explicit path override (e.g. from --config-file flag).

    Returns:
        Resolved config file path.

    """
    if override:
        return Path(override)
    env = os.environ.get("TOYOTA_CONFIG_FILE")
    if env:
        return Path(env)
    return DEFAULT_CONFIG_PATH


def load_config(path: Path | None = None) -> dict[str, Any]:
    """Load config from disk.

    Args:
        path: Path to config file. Uses resolved default if None.

    Returns:
        Config dict. Returns empty dict if file does not exist.

    Raises:
        json.JSONDecodeError: If file exists but is not valid JSON.

    """
    resolved = path or get_config_path()
    if not resolved.exists():
        return {}
    return json.loads(resolved.read_text())


def save_config(config: dict[str, Any], path: Path | None = None) -> None:
    """Save config to disk.

    Args:
        config: Config dict to write.
        path: Path to config file. Uses resolved default if None.

    """
    resolved = path or get_config_path()
    resolved.parent.mkdir(parents=True, exist_ok=True)
    resolved.write_text(json.dumps(config, indent=2))


def format_ts(iso_string: str | None, date_format: str = "human") -> str:
    """Format an ISO 8601 timestamp string for display.

    Args:
        iso_string: ISO 8601 datetime string (e.g. "2026-03-24T08:04:00Z").
        date_format: "human" for "24 Mar 2026, 08:04 UTC"; "iso" to pass through unchanged.

    Returns:
        Formatted timestamp string, or the original string if parsing fails.

    """
    if iso_string is None:
        return ""
    if date_format == "iso":
        return iso_string
    try:
        # Handle both Z suffix and +00:00 offset
        normalized = iso_string.replace("Z", "+00:00")
        dt = datetime.fromisoformat(normalized)
        # Convert to UTC for display
        dt_utc = dt.astimezone(timezone.utc)
        return dt_utc.strftime("%d %b %Y, %H:%M UTC")
    except (ValueError, AttributeError):
        return iso_string


def convert_distance(
    meters: int | float | None, distance_unit: str = "km"
) -> tuple[float | None, str]:
    """Convert a distance in meters to the configured unit.

    Args:
        meters: Distance in meters.
        distance_unit: "km" or "mi".

    Returns:
        Tuple of (converted_value, unit_label). Value is None if meters is None.

    """
    if meters is None:
        return None, distance_unit
    km = meters / 1000.0
    if distance_unit == "mi":
        return km * 0.621371, "mi"
    return km, "km"
