"""Weather tool."""

from __future__ import annotations

import json as _wx_json
import logging
from datetime import datetime, timedelta, timezone

from fabledassistant.services.tools._registry import tool

logger = logging.getLogger(__name__)


@tool(
    name="get_weather",
    description=(
        "Get the weather forecast. By default returns today only — use days=7 when the user "
        "explicitly asks for a multi-day forecast or 'this week'. "
        "Pass a city/region name to look up any location, or omit to get the user's configured home/work locations."
    ),
    parameters={
        "location": {"type": "string", "description": "City/region to look up, or 'home'/'work' for saved locations. Omit for all saved."},
        "days": {"type": "integer", "description": "Number of days to return (1–8). Default 1 (today only). Use 7 or 8 when the user asks for a weekly forecast or multiple days."},
    },
    read_only=True,
    briefing=True,
)
async def get_weather_tool(*, user_id, arguments, **_ctx):
    from fabledassistant.services.weather import (
        _fetch_open_meteo,
        geocode,
        get_cached_weather,
        get_temp_unit,
        parse_forecast,
        refresh_location_cache,
    )

    location = (arguments.get("location") or "").strip()
    num_days = max(1, min(8, int(arguments.get("days") or 1)))
    temp_unit = await get_temp_unit(user_id)

    def _apply_unit(days: list[dict]) -> list[dict]:
        if temp_unit != "F":
            return days
        def _c_to_f(v: float | None) -> float | None:
            return round(v * 9 / 5 + 32, 1) if v is not None else None
        return [
            {**d, "temp_max": _c_to_f(d.get("temp_max")), "temp_min": _c_to_f(d.get("temp_min"))}
            for d in days
        ]

    _known = {"home", "work", "all", ""}
    if location.lower() not in _known:
        try:
            lat, lon, label = await geocode(location)
            raw = await _fetch_open_meteo(lat, lon)
            days = _apply_unit(parse_forecast(raw))[:num_days]
            return {"success": True, "data": {"locations": [{
                "location_key": "query",
                "location_label": label,
                "fetched_at": datetime.now(timezone.utc).isoformat(),
                "days": days,
                "temp_unit": temp_unit,
                "changes_since_last_fetch": [],
            }]}}
        except Exception as e:
            return {"success": False, "error": f"Could not get weather for '{location}': {e}"}

    locations = await get_cached_weather(user_id)
    if location.lower() not in ("all", ""):
        locations = [loc for loc in locations if loc["location_key"] == location.lower()]
    now_utc = datetime.now(timezone.utc)
    stale_cutoff = now_utc - timedelta(hours=6)
    stale_keys = []
    for loc in locations:
        try:
            fetched = datetime.fromisoformat(loc.get("fetched_at", ""))
        except Exception:
            fetched = None
        if fetched is None or fetched < stale_cutoff:
            stale_keys.append(loc["location_key"])
    if stale_keys:
        try:
            from fabledassistant.services.settings import get_setting as _wx_get_setting
            raw_cfg = await _wx_get_setting(user_id, "journal_config", "{}")
            cfg = _wx_json.loads(raw_cfg) if isinstance(raw_cfg, str) else (raw_cfg or {})
            cfg_locs = cfg.get("locations", {}) if isinstance(cfg, dict) else {}
            for key in stale_keys:
                meta = cfg_locs.get(key) or {}
                if meta.get("lat") and meta.get("lon"):
                    try:
                        await refresh_location_cache(
                            user_id=user_id,
                            location_key=key,
                            location_label=meta.get("label", key),
                            lat=meta["lat"],
                            lon=meta["lon"],
                        )
                    except Exception:
                        logger.debug("Weather refresh failed for %s", key, exc_info=True)
            locations = await get_cached_weather(user_id)
            if location.lower() not in ("all", ""):
                locations = [loc for loc in locations if loc["location_key"] == location.lower()]
        except Exception:
            logger.debug("Weather staleness refresh failed", exc_info=True)

    stamped_locations = []
    for loc in locations:
        days = _apply_unit(loc.get("days", []))[:num_days]
        try:
            fetched = datetime.fromisoformat(loc.get("fetched_at", ""))
            age_h = (now_utc - fetched).total_seconds() / 3600.0
        except Exception:
            age_h = None
        stamped_locations.append({
            **loc,
            "days": days,
            "temp_unit": temp_unit,
            "cache_age_hours": round(age_h, 1) if age_h is not None else None,
            "is_stale": age_h is not None and age_h > 12.0,
        })
    return {"success": True, "data": {"locations": stamped_locations}}
