#!/usr/bin/env python
"""
R2-B end-to-end approval round-trip spike.

Usage:
  # Print URL only (you can click it in a browser running the server):
  python scripts/send_test_approval.py

  # Bypass the email and exercise the full POST against a TestClient:
  python scripts/send_test_approval.py --simulate-click approve
  python scripts/send_test_approval.py --simulate-click deny

This is the actual proof that the email + per-voter approval click
round-trip works against the real schema (`family_member`,
`meal_plan_item`, `meal_plan_vote`). If the script exits 0 with
`item_status=approved` (or `denied`) the spike is green.
"""

from __future__ import annotations

import argparse
import os
import sys
import uuid
from datetime import date, timedelta
from pathlib import Path

# Make backend/ importable when invoked from repo root.
_REPO_ROOT = Path(__file__).resolve().parent.parent
_BACKEND_ROOT = _REPO_ROOT / "backend"
if str(_BACKEND_ROOT) not in sys.path:
    sys.path.insert(0, str(_BACKEND_ROOT))

# DATABASE_URL must be set before importing app.config.
os.environ.setdefault(
    "DATABASE_URL",
    os.environ.get(
        "TEST_DATABASE_URL",
        "postgresql://mealplanner:password@localhost:5432/mealplanner_test",
    ),
)


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "--simulate-click",
        choices=["approve", "deny"],
        help="Bypass email; POST the vote via TestClient and assert success.",
    )
    parser.add_argument(
        "--base-url",
        default="http://localhost:8000",
        help="Base URL for the printed link (informational only).",
    )
    args = parser.parse_args()

    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker

    from app.config import settings
    from app.models import (
        FamilyMember,
        FamilyMemberRole,
        FamilyProfile,
        MealPlan,
        MealPlanItem,
        MealPlanStatus,
        MealType,
        Recipe,
    )
    from app.services import approval as approval_service
    from app.services.email import get_email_backend

    engine = create_engine(
        settings.DATABASE_URL.replace("postgresql://", "postgresql+psycopg2://")
    )
    Session = sessionmaker(bind=engine, autoflush=False, autocommit=False)
    db = Session()

    # ------------------------------------------------------------------
    # Bootstrap a minimal scenario. Suffix everything with a UUID4 so the
    # script is idempotent and can run repeatedly without unique-constraint
    # collisions.
    # ------------------------------------------------------------------
    suffix = uuid.uuid4().hex[:8]

    profile = FamilyProfile(
        name=f"Spike Family {suffix}",
        household_size=1,
        adult_count=1,
        child_count=0,
    )
    db.add(profile)
    db.flush()

    voter = FamilyMember(
        family_profile_id=profile.id,
        name="Spike Voter",
        email=f"spike+{suffix}@example.com",
        role=FamilyMemberRole.ADULT,
    )
    db.add(voter)
    db.flush()

    recipe = Recipe(
        family_profile_id=profile.id,
        name=f"Spike Pasta {suffix}",
        servings=2,
        ingredients=[{"name": "pasta", "qty": "200g"}],
        instructions=["Boil water", "Cook pasta"],
        is_manually_added=True,
    )
    db.add(recipe)
    db.flush()

    plan = MealPlan(
        family_profile_id=profile.id,
        week_start_date=date.today() + timedelta(days=(7 - date.today().weekday())),
        status=MealPlanStatus.DRAFT,
    )
    db.add(plan)
    db.flush()

    item = MealPlanItem(
        meal_plan_id=plan.id,
        recipe_id=recipe.id,
        day_of_week=1,
        meal_type=MealType.DINNER,
    )
    db.add(item)
    db.commit()

    token = approval_service.issue_token(item.id, voter.id)
    url = f"{args.base_url}/api/meals/vote/{item.id}?token={token}"

    # Send via configured email backend (Console writes to stdout + outbox).
    backend = get_email_backend()
    subject = "Action required: please vote on this week's meal"
    html = (
        f"<p>Hi {voter.name}, please review this meal:</p>"
        f"<p><strong>{recipe.name}</strong></p>"
        f'<p><a href="{url}">Open the approval page</a></p>'
    )
    text = f"Hi {voter.name}, please review {recipe.name}: {url}"
    backend.send(to=voter.email, subject=subject, html=html, text=text)

    print(f"item_id={item.id}")
    print(f"voter_id={voter.id}")
    print(f"approval_url={url}")

    if args.simulate_click is None:
        return 0

    # ------------------------------------------------------------------
    # End-to-end proof: drive the POST through a TestClient.
    # ------------------------------------------------------------------
    from fastapi.testclient import TestClient

    from app.main import app

    with TestClient(app) as client:
        # Render the GET page first to mirror a real click.
        r_get = client.get(f"/api/meals/vote/{item.id}", params={"token": token})
        assert r_get.status_code == 200, (r_get.status_code, r_get.text)
        assert "text/html" in r_get.headers.get("content-type", "")

        r_post = client.post(
            f"/api/meals/vote/{item.id}",
            params={"token": token},
            json={"vote": args.simulate_click},
        )
        assert r_post.status_code == 200, (r_post.status_code, r_post.text)
        body = r_post.json()
        print(f"item_status={body['item_status']}")
        assert body["status"] == "recorded"

        # Single-use: a second POST must 409.
        r_post2 = client.post(
            f"/api/meals/vote/{item.id}",
            params={"token": token},
            json={"vote": args.simulate_click},
        )
        assert r_post2.status_code == 409, (r_post2.status_code, r_post2.text)
        print("single_use=enforced")

    return 0


if __name__ == "__main__":
    sys.exit(main())
