# tests/api/test_meal_plans.py
"""Integration tests for /api/v1/meal-plans/ endpoints."""
from __future__ import annotations

from unittest.mock import MagicMock

import pytest
from fastapi.testclient import TestClient

from app.cloud_session import get_session
from app.db.session import get_store
from app.main import app

client = TestClient(app)


def _make_session(tier: str = "free") -> MagicMock:
    m = MagicMock()
    m.tier = tier
    m.has_byok = False
    return m


def _make_store() -> MagicMock:
    m = MagicMock()
    m.create_meal_plan.return_value = {
        "id": 1, "week_start": "2026-04-14",
        "meal_types": ["dinner"], "created_at": "2026-04-12T10:00:00",
    }
    m.list_meal_plans.return_value = []
    m.get_meal_plan.return_value = None
    m.get_plan_slots.return_value = []
    m.upsert_slot.return_value = {
        "id": 1, "plan_id": 1, "day_of_week": 0, "meal_type": "dinner",
        "recipe_id": 42, "recipe_title": "Pasta", "servings": 2.0, "custom_label": None,
    }
    m.get_inventory.return_value = []
    m.get_plan_recipes.return_value = []
    m.get_prep_session_for_plan.return_value = None
    m.create_prep_session.return_value = {
        "id": 1, "plan_id": 1, "scheduled_date": "2026-04-13",
        "status": "draft", "created_at": "2026-04-12T10:00:00",
    }
    m.get_prep_tasks.return_value = []
    m.bulk_insert_prep_tasks.return_value = []
    return m


@pytest.fixture()
def free_session():
    session = _make_session("free")
    store = _make_store()
    app.dependency_overrides[get_session] = lambda: session
    app.dependency_overrides[get_store] = lambda: store
    yield store
    app.dependency_overrides.clear()


@pytest.fixture()
def paid_session():
    session = _make_session("paid")
    store = _make_store()
    app.dependency_overrides[get_session] = lambda: session
    app.dependency_overrides[get_store] = lambda: store
    yield store
    app.dependency_overrides.clear()


def test_create_plan_free_tier_locks_to_dinner(free_session):
    resp = client.post("/api/v1/meal-plans/", json={
        "week_start": "2026-04-13", "meal_types": ["breakfast", "dinner"]
    })
    assert resp.status_code == 200
    # Free tier forced to dinner-only regardless of request
    free_session.create_meal_plan.assert_called_once_with("2026-04-13", ["dinner"])


def test_create_plan_paid_tier_respects_meal_types(paid_session):
    resp = client.post("/api/v1/meal-plans/", json={
        "week_start": "2026-04-13", "meal_types": ["breakfast", "lunch", "dinner"]
    })
    assert resp.status_code == 200
    paid_session.create_meal_plan.assert_called_once_with(
        "2026-04-13", ["breakfast", "lunch", "dinner"]
    )


def test_list_plans_returns_200(free_session):
    resp = client.get("/api/v1/meal-plans/")
    assert resp.status_code == 200
    assert resp.json() == []


def test_upsert_slot_returns_200(free_session):
    free_session.get_meal_plan.return_value = {
        "id": 1, "week_start": "2026-04-14", "meal_types": ["dinner"],
        "created_at": "2026-04-12T10:00:00",
    }
    resp = client.put(
        "/api/v1/meal-plans/1/slots/0/dinner",
        json={"recipe_id": 42, "servings": 2.0},
    )
    assert resp.status_code == 200


def test_get_shopping_list_returns_200(free_session):
    free_session.get_meal_plan.return_value = {
        "id": 1, "week_start": "2026-04-14", "meal_types": ["dinner"],
        "created_at": "2026-04-12T10:00:00",
    }
    resp = client.get("/api/v1/meal-plans/1/shopping-list")
    assert resp.status_code == 200
    body = resp.json()
    assert "gap_items" in body
    assert "covered_items" in body
