from __future__ import annotations

from collections import Counter
from typing import Any

from app.services.repository import repo


def _overlap(left: list[str], right: list[str]) -> list[str]:
    return sorted(set(left) & set(right))


class PlannerService:
    def generate(self, *, week_start: str, anchors: list[str], target_meals: int) -> dict[str, Any]:
        suggestions = [
            item for item in repo.list_suggestions()
            if item.get("status") in {"approved", "suggested", "saved"}
        ]
        chosen: list[dict[str, Any]] = []
        used_ids: set[str] = set()
        for item in sorted(suggestions, key=lambda entry: entry.get("score", 0), reverse=True):
            haystack = " ".join([str(item.get("title") or ""), " ".join(item.get("ingredients") or []), " ".join(item.get("tags") or [])]).lower()
            if anchors and not any(anchor.strip().lower() in haystack for anchor in anchors if anchor.strip()):
                continue
            chosen.append(item)
            used_ids.add(str(item.get("id")))
            if len(chosen) >= min(len(anchors), target_meals):
                break
        ingredient_counter: Counter[str] = Counter()
        for item in chosen:
            ingredient_counter.update(item.get("ingredients") or [])
        ranked = sorted(
            (item for item in suggestions if str(item.get("id")) not in used_ids),
            key=lambda entry: (
                len(_overlap(list(ingredient_counter), entry.get("ingredients") or [])),
                entry.get("score", 0),
            ),
            reverse=True,
        )
        for item in ranked:
            if len(chosen) >= target_meals:
                break
            chosen.append(item)
            used_ids.add(str(item.get("id")))
            ingredient_counter.update(item.get("ingredients") or [])
        meals: list[dict[str, Any]] = []
        shared = [name for name, count in ingredient_counter.items() if count >= 2]
        for item in chosen[:target_meals]:
            overlap = _overlap(shared, item.get("ingredients") or [])
            note = "Reuses: " + ", ".join(overlap[:4]) if overlap else "Adds variety without blowing up the ingredient list."
            meals.append(
                {
                    "suggestion_id": item.get("id"),
                    "title": item.get("title"),
                    "url": item.get("url"),
                    "score": item.get("score"),
                    "ingredients": item.get("ingredients") or [],
                    "note": note,
                }
            )
        return {
            "week_start": week_start,
            "anchors": anchors,
            "target_meals": target_meals,
            "shared_ingredients": shared[:12],
            "meals": meals,
            "summary": f"Built {len(meals)} meals with {len(shared[:12])} shared ingredient lanes.",
        }


planner = PlannerService()

