"""Coffee consumption tracker — stores data locally in ~/.caffeinate_me/tracker.json."""

import json
from datetime import datetime, timedelta
from pathlib import Path
from typing import Any, Dict, List, Optional

DATA_DIR: Path = Path.home() / ".caffeinate_me"
TRACKER_FILE: Path = DATA_DIR / "tracker.json"

# ---------------------------------------------------------------------------
# Achievement definitions
# ---------------------------------------------------------------------------

ACHIEVEMENTS: Dict[str, Dict[str, str]] = {
    "first_cup": {
        "name": "First Cup",
        "description": "Logged your very first coffee!",
        "icon": "☕",
    },
    "triple_shot": {
        "name": "Triple Shot",
        "description": "Had 3 coffees in one day!",
        "icon": "🔥",
    },
    "early_bird": {
        "name": "Early Bird",
        "description": "Had coffee before 6 AM!",
        "icon": "🌅",
    },
    "night_owl": {
        "name": "Night Owl",
        "description": "Had coffee after 10 PM!",
        "icon": "🦉",
    },
    "week_warrior": {
        "name": "Week Warrior",
        "description": "Had coffee every day for 7 consecutive days!",
        "icon": "🏆",
    },
    "century_club": {
        "name": "Century Club",
        "description": "Logged 100 coffees total!",
        "icon": "💯",
    },
    "variety_seeker": {
        "name": "Variety Seeker",
        "description": "Tried 5 different coffee types!",
        "icon": "🎨",
    },
}

# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------


def _ensure_data_dir() -> None:
    DATA_DIR.mkdir(parents=True, exist_ok=True)


def _load_data() -> Dict[str, Any]:
    if not TRACKER_FILE.exists():
        return {"entries": [], "achievements": []}
    try:
        with open(TRACKER_FILE) as fh:
            return json.load(fh)
    except (json.JSONDecodeError, OSError):
        return {"entries": [], "achievements": []}


def _save_data(data: Dict[str, Any]) -> None:
    _ensure_data_dir()
    with open(TRACKER_FILE, "w") as fh:
        json.dump(data, fh, indent=2)


def _check_achievements(data: Dict[str, Any]) -> List[str]:
    """Evaluate all achievement conditions and return newly unlocked keys."""
    entries: List[Dict[str, Any]] = data["entries"]
    already_unlocked: List[str] = data.get("achievements", [])
    newly_unlocked: List[str] = []

    def unlock(key: str) -> None:
        if key not in already_unlocked:
            already_unlocked.append(key)
            newly_unlocked.append(key)

    if not entries:
        data["achievements"] = already_unlocked
        return newly_unlocked

    # First Cup
    if len(entries) >= 1:
        unlock("first_cup")

    # Century Club
    if len(entries) >= 100:
        unlock("century_club")

    # Early Bird — coffee before 6 AM
    if any(datetime.fromisoformat(e["timestamp"]).hour < 6 for e in entries):
        unlock("early_bird")

    # Night Owl — coffee at or after 10 PM
    if any(datetime.fromisoformat(e["timestamp"]).hour >= 22 for e in entries):
        unlock("night_owl")

    # Triple Shot — 3+ coffees on the same day
    daily_counts: Dict[str, int] = {}
    for e in entries:
        day = datetime.fromisoformat(e["timestamp"]).date().isoformat()
        daily_counts[day] = daily_counts.get(day, 0) + 1
    if any(v >= 3 for v in daily_counts.values()):
        unlock("triple_shot")

    # Week Warrior — 7 consecutive days
    unique_days = sorted({datetime.fromisoformat(e["timestamp"]).date() for e in entries})
    for i in range(len(unique_days) - 6):
        if (unique_days[i + 6] - unique_days[i]).days == 6:
            unlock("week_warrior")
            break

    # Variety Seeker — 5 distinct coffee types
    types = {e.get("coffee_type") for e in entries if e.get("coffee_type")}
    if len(types) >= 5:
        unlock("variety_seeker")

    data["achievements"] = already_unlocked
    return newly_unlocked


# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------


def log_coffee(
    coffee_type: Optional[str] = None,
    mood: Optional[str] = None,
) -> List[str]:
    """
    Log a coffee consumption entry.

    Args:
        coffee_type: Type of coffee consumed (e.g. 'espresso').
        mood: Current mood (e.g. 'energetic').

    Returns:
        List of newly unlocked achievement keys.
    """
    data = _load_data()

    entry: Dict[str, Any] = {"timestamp": datetime.now().isoformat()}
    if coffee_type:
        entry["coffee_type"] = coffee_type
    if mood:
        entry["mood"] = mood

    data["entries"].append(entry)
    newly_unlocked = _check_achievements(data)
    _save_data(data)
    return newly_unlocked


def get_stats() -> Dict[str, Any]:
    """
    Return a summary of coffee consumption statistics.

    Returns a dict with keys: total, today, week, favorite_type,
    avg_per_day, achievements, all_achievements.
    """
    data = _load_data()
    entries: List[Dict[str, Any]] = data["entries"]

    now = datetime.now()
    today = now.date()
    week_ago = today - timedelta(days=7)

    today_count = sum(
        1 for e in entries if datetime.fromisoformat(e["timestamp"]).date() == today
    )
    week_count = sum(
        1 for e in entries if datetime.fromisoformat(e["timestamp"]).date() > week_ago
    )

    # Favourite coffee type
    type_counts: Dict[str, int] = {}
    for e in entries:
        ct = e.get("coffee_type")
        if ct:
            type_counts[ct] = type_counts.get(ct, 0) + 1
    favorite = max(type_counts, key=lambda k: type_counts[k]) if type_counts else None

    # Average per day
    if entries:
        first_day = min(datetime.fromisoformat(e["timestamp"]).date() for e in entries)
        days_elapsed = max((today - first_day).days + 1, 1)
        avg = round(len(entries) / days_elapsed, 1)
    else:
        avg = 0.0

    return {
        "total": len(entries),
        "today": today_count,
        "week": week_count,
        "favorite_type": favorite,
        "avg_per_day": avg,
        "achievements": data.get("achievements", []),
        "all_achievements": ACHIEVEMENTS,
    }


def export_data(format: str = "json") -> str:
    """
    Export tracker data as a string.

    Args:
        format: 'json' or 'csv'.

    Returns:
        Formatted data string.
    """
    data = _load_data()

    if format == "csv":
        lines = ["timestamp,coffee_type,mood"]
        for e in data["entries"]:
            lines.append(
                f"{e.get('timestamp', '')},"
                f"{e.get('coffee_type', '')},"
                f"{e.get('mood', '')}"
            )
        return "\n".join(lines)

    return json.dumps(data, indent=2)


def clear_data() -> None:
    """Erase all tracking data (irreversible)."""
    _save_data({"entries": [], "achievements": []})
