from fastapi import APIRouter, HTTPException, Request

from app.services.repository import repo
from app.services.recipe_search import recipe_search
from app.services.store import JsonStore


router = APIRouter(prefix="/api", tags=["dashboard"])
store = JsonStore()


def usable_results(items):
    return [entry for entry in items if str(entry.get("status") or "suggested") != "rejected"]


def _find_suggestion(suggestion_id: str | None):
    if not suggestion_id:
        return None
    return next((item for item in repo.list_suggestions() if str(item.get("id")) == str(suggestion_id)), None)


def _find_existing_open_import_flag(recipe_url: str, kitchenowl_recipe_id: str | int | None):
    recipe_url = str(recipe_url or "").strip().lower()
    recipe_id = str(kitchenowl_recipe_id or "").strip()
    for item in repo.list_import_flags():
        if str(item.get("status") or "open") != "open":
            continue
        item_url = str(item.get("recipe_url") or "").strip().lower()
        item_recipe_id = str(item.get("kitchenowl_recipe_id") or "").strip()
        if recipe_id and item_recipe_id and recipe_id == item_recipe_id:
            return item
        if recipe_url and item_url and recipe_url == item_url:
            return item
    return None


@router.get("/health")
async def health():
    return {"status": "ok", "backend": repo.backend}


@router.get("/dashboard/summary")
async def summary():
    profile = repo.get_profile()
    suggestions = repo.list_suggestions()
    plans = repo.list_meal_plans()
    failed_searches = repo.recent_failed_searches(limit=6)
    import_flags = repo.list_import_flags()
    counts = {
        "suggested": sum(1 for item in suggestions if item.get("status") == "suggested"),
        "approved": sum(1 for item in suggestions if item.get("status") == "approved"),
        "saved": sum(1 for item in suggestions if item.get("status") == "saved"),
        "rejected": sum(1 for item in suggestions if item.get("status") == "rejected"),
        "plans": len(plans),
        "failed_searches": len(repo.list_failed_searches()),
        "open_import_flags": sum(1 for item in import_flags if str(item.get("status") or "open") == "open"),
    }
    return {
        "backend": repo.backend,
        "profile": profile,
        "counts": counts,
        "recent_suggestions": repo.recent_suggestions(),
        "recent_plans": list(reversed(plans[-4:])),
        "recent_failed_searches": failed_searches,
        "recent_import_flags": repo.recent_import_flags(limit=6),
    }


@router.get("/failed-searches")
async def failed_searches():
    return {"status": "ok", "items": repo.list_failed_searches()}


@router.get("/failed-searches/{failed_search_id}/results")
async def failed_search_results(failed_search_id: str):
    item = next((entry for entry in repo.list_failed_searches() if str(entry.get("id")) == str(failed_search_id)), None)
    if not item:
        raise HTTPException(status_code=404, detail="Failed search not found.")
    query = str(item.get("query") or "").strip()
    if not query:
        raise HTTPException(status_code=400, detail="Failed search query is empty.")
    all_results = recipe_search.search(query, limit=10)
    results = usable_results(all_results)
    updates = {
        "last_checked_at": store.now(),
        "updated_at": store.now(),
        "result_count": len(results),
        "sample_titles": [str(entry.get("title") or "") for entry in results[:4]],
    }
    if results:
        updates["status"] = "resolved-with-recipes"
        updates["resolved_at"] = str(item.get("resolved_at") or store.now())
    saved = repo.update_failed_search(str(item.get("id")), updates) or {**item, **updates}
    return {"status": "ok", "item": saved, "results": results}


@router.post("/failed-searches/refresh")
async def refresh_failed_searches():
    items = repo.list_failed_searches()
    refreshed = []
    for item in items:
        query = str(item.get("query") or "").strip()
        status = str(item.get("status") or "open")
        if not query or status != "open":
            refreshed.append(item)
            continue
        all_results = recipe_search.search(query, limit=10)
        results = usable_results(all_results)
        preview_titles = [str(entry.get("title") or "") for entry in results[:4] if str(entry.get("title") or "").strip()]
        result_count = len(results)
        updates = {
            "last_checked_at": store.now(),
            "result_count": result_count,
            "sample_titles": preview_titles,
        }
        if result_count > 0:
            updates["status"] = "resolved-with-recipes"
            updates["resolved_at"] = store.now()
        saved = repo.update_failed_search(str(item.get("id")), updates) or {**item, **updates}
        refreshed.append(saved)
    return {"status": "ok", "items": refreshed}


@router.get("/import-flags")
async def list_import_flags():
    return {"status": "ok", "items": repo.list_import_flags()}


@router.post("/import-flags")
async def create_import_flag(request: Request):
    payload = await request.json()
    suggestion_id = str(payload.get("suggestion_id") or "").strip() or None
    suggestion = _find_suggestion(suggestion_id)
    if suggestion_id and not suggestion:
        raise HTTPException(status_code=404, detail="Suggestion not found.")

    recipe_title = str(payload.get("recipe_title") or (suggestion or {}).get("title") or ((suggestion or {}).get("payload") or {}).get("name") or "").strip()
    recipe_url = str(payload.get("recipe_url") or ((suggestion or {}).get("payload") or {}).get("source") or (suggestion or {}).get("url") or "").strip()
    issue_type = str(payload.get("issue_type") or "formatting").strip().lower() or "formatting"
    notes = str(payload.get("notes") or "").strip()
    kitchenowl_recipe_id = payload.get("kitchenowl_recipe_id")
    if kitchenowl_recipe_id in {None, "", 0}:
        kitchenowl_recipe_id = (((suggestion or {}).get("kitchenowl_result") or {}).get("recipe") or {}).get("id")

    if not notes:
        raise HTTPException(status_code=400, detail="Issue notes are required.")
    if not recipe_title and not recipe_url and not kitchenowl_recipe_id:
        raise HTTPException(status_code=400, detail="Provide at least a recipe title, recipe URL, or KitchenOwl recipe id.")

    existing = _find_existing_open_import_flag(recipe_url, kitchenowl_recipe_id)
    if existing:
        history = list(existing.get("notes_history") or [])
        history.append({"at": store.now(), "issue_type": issue_type, "notes": notes})
        updates = {
            "updated_at": store.now(),
            "last_flagged_at": store.now(),
            "issue_type": issue_type,
            "notes": notes,
            "notes_history": history[-20:],
            "flag_count": int(existing.get("flag_count") or 1) + 1,
            "recipe_title": recipe_title or existing.get("recipe_title"),
            "recipe_url": recipe_url or existing.get("recipe_url"),
            "kitchenowl_recipe_id": kitchenowl_recipe_id or existing.get("kitchenowl_recipe_id"),
            "suggestion_id": suggestion_id or existing.get("suggestion_id"),
            "kitchenowl_status": (suggestion or {}).get("kitchenowl_status") or existing.get("kitchenowl_status"),
        }
        saved = repo.update_import_flag(str(existing.get("id")), updates) or {**existing, **updates}
        return {"status": "ok", "item": saved, "deduplicated": True}

    item = {
        "id": store.new_id("import-flag"),
        "status": "open",
        "issue_type": issue_type,
        "notes": notes,
        "notes_history": [{"at": store.now(), "issue_type": issue_type, "notes": notes}],
        "flag_count": 1,
        "created_at": store.now(),
        "updated_at": store.now(),
        "last_flagged_at": store.now(),
        "suggestion_id": suggestion_id,
        "recipe_title": recipe_title,
        "recipe_url": recipe_url,
        "kitchenowl_recipe_id": kitchenowl_recipe_id,
        "kitchenowl_status": (suggestion or {}).get("kitchenowl_status"),
    }
    saved = repo.log_import_flag(item)
    return {"status": "ok", "item": saved, "deduplicated": False}


@router.post("/import-flags/{import_flag_id}/resolve")
async def resolve_import_flag(import_flag_id: str, request: Request):
    payload = await request.json()
    current = next((entry for entry in repo.list_import_flags() if str(entry.get("id")) == str(import_flag_id)), None)
    if not current:
        raise HTTPException(status_code=404, detail="Import flag not found.")
    resolution_notes = str(payload.get("resolution_notes") or "").strip()
    updates = {
        "status": "resolved",
        "updated_at": store.now(),
        "resolved_at": store.now(),
    }
    if resolution_notes:
        updates["resolution_notes"] = resolution_notes
    saved = repo.update_import_flag(import_flag_id, updates) or {**current, **updates}
    return {"status": "ok", "item": saved}
