#!/usr/bin/env python3
"""
Chinese-Style Shared Dinner Fairness Analysis
Evaluates menu fairness across 10 diners with diverse constraints and preferences
"""

import pandas as pd
import json
from datetime import datetime

# ============================================================================
# DINER PROFILES
# ============================================================================

diners = [
    {
        "id": 1,
        "name": "Alice",
        "allergies": ["peanuts", "tree nuts"],
        "dietary_restrictions": [],
        "budget_per_person": 50,
        "cuisine_preferences": ["Sichuan", "Cantonese"],
        "dislikes": ["organ meats", "sea cucumber"]
    },
    {
        "id": 2,
        "name": "Bob",
        "allergies": [],
        "dietary_restrictions": ["vegetarian"],
        "budget_per_person": 40,
        "cuisine_preferences": ["Cantonese", "Shanghai"],
        "dislikes": ["spicy food"]
    },
    {
        "id": 3,
        "name": "Carol",
        "allergies": ["shellfish"],
        "dietary_restrictions": [],
        "budget_per_person": 60,
        "cuisine_preferences": ["Sichuan", "Hunan"],
        "dislikes": ["bitter melon"]
    },
    {
        "id": 4,
        "name": "David",
        "allergies": [],
        "dietary_restrictions": ["halal"],
        "budget_per_person": 45,
        "cuisine_preferences": ["Xinjiang", "Beijing"],
        "dislikes": ["tofu"]
    },
    {
        "id": 5,
        "name": "Emma",
        "allergies": ["soy"],
        "dietary_restrictions": [],
        "budget_per_person": 55,
        "cuisine_preferences": ["Cantonese", "Fujian"],
        "dislikes": ["chicken feet", "jellyfish"]
    },
    {
        "id": 6,
        "name": "Frank",
        "allergies": [],
        "dietary_restrictions": ["vegan"],
        "budget_per_person": 35,
        "cuisine_preferences": ["Sichuan", "Cantonese"],
        "dislikes": ["mock meats"]
    },
    {
        "id": 7,
        "name": "Grace",
        "allergies": ["gluten"],
        "dietary_restrictions": [],
        "budget_per_person": 70,
        "cuisine_preferences": ["Cantonese", "Shanghai"],
        "dislikes": ["century eggs"]
    },
    {
        "id": 8,
        "name": "Henry",
        "allergies": [],
        "dietary_restrictions": [],
        "budget_per_person": 50,
        "cuisine_preferences": ["Sichuan", "Hunan", "Xinjiang"],
        "dislikes": ["fish with bones"]
    },
    {
        "id": 9,
        "name": "Iris",
        "allergies": ["dairy"],
        "dietary_restrictions": ["pescatarian"],
        "budget_per_person": 45,
        "cuisine_preferences": ["Cantonese", "Fujian"],
        "dislikes": ["offal"]
    },
    {
        "id": 10,
        "name": "Jack",
        "allergies": [],
        "dietary_restrictions": [],
        "budget_per_person": 40,
        "cuisine_preferences": ["Beijing", "Shanghai"],
        "dislikes": ["spicy food", "fermented foods"]
    }
]

# ============================================================================
# AI-GENERATED MENU
# ============================================================================

menu = {
    "total_cost_per_person": 35,
    "dishes": [
        {
            "name": "Steamed Jasmine Rice",
            "cuisine": "Cantonese",
            "price": 20,
            "serves": 10,
            "allergens": [],
            "contains_meat": False,
            "contains_seafood": False,
            "is_spicy": False,
            "contains_gluten": False,
            "contains_soy": False,
            "contains_dairy": False,
            "halal": True,
            "ingredients": ["rice", "water"]
        },
        {
            "name": "Mapo Tofu (Mild)",
            "cuisine": "Sichuan",
            "price": 35,
            "serves": 4,
            "allergens": ["soy"],
            "contains_meat": True,
            "contains_seafood": False,
            "is_spicy": False,
            "contains_gluten": False,
            "contains_soy": True,
            "contains_dairy": False,
            "halal": False,
            "ingredients": ["tofu", "ground pork", "fermented bean paste", "scallions"]
        },
        {
            "name": "Stir-Fried Bok Choy with Garlic",
            "cuisine": "Cantonese",
            "price": 28,
            "serves": 6,
            "allergens": [],
            "contains_meat": False,
            "contains_seafood": False,
            "is_spicy": False,
            "contains_gluten": False,
            "contains_soy": False,
            "contains_dairy": False,
            "halal": True,
            "ingredients": ["bok choy", "garlic", "vegetable oil", "salt"]
        },
        {
            "name": "Kung Pao Chicken (Mild)",
            "cuisine": "Sichuan",
            "price": 42,
            "serves": 5,
            "allergens": ["peanuts", "soy"],
            "contains_meat": True,
            "contains_seafood": False,
            "is_spicy": False,
            "contains_gluten": False,
            "contains_soy": True,
            "contains_dairy": False,
            "halal": True,
            "ingredients": ["chicken", "peanuts", "bell peppers", "soy sauce", "dried chilies"]
        },
        {
            "name": "Steamed Fish with Ginger",
            "cuisine": "Cantonese",
            "price": 55,
            "serves": 6,
            "allergens": ["soy"],
            "contains_meat": False,
            "contains_seafood": True,
            "is_spicy": False,
            "contains_gluten": False,
            "contains_soy": True,
            "contains_dairy": False,
            "halal": True,
            "ingredients": ["sea bass", "ginger", "scallions", "soy sauce"]
        },
        {
            "name": "Buddha's Delight (Mixed Vegetables)",
            "cuisine": "Cantonese",
            "price": 32,
            "serves": 6,
            "allergens": [],
            "contains_meat": False,
            "contains_seafood": False,
            "is_spicy": False,
            "contains_gluten": False,
            "contains_soy": False,
            "contains_dairy": False,
            "halal": True,
            "ingredients": ["shiitake mushrooms", "snow peas", "carrots", "baby corn", "bamboo shoots"]
        },
        {
            "name": "Braised Lamb with Cumin",
            "cuisine": "Xinjiang",
            "price": 48,
            "serves": 5,
            "allergens": [],
            "contains_meat": True,
            "contains_seafood": False,
            "is_spicy": False,
            "contains_gluten": False,
            "contains_soy": False,
            "contains_dairy": False,
            "halal": True,
            "ingredients": ["lamb", "cumin", "onions", "bell peppers"]
        },
        {
            "name": "Stir-Fried Green Beans",
            "cuisine": "Sichuan",
            "price": 26,
            "serves": 6,
            "allergens": [],
            "contains_meat": False,
            "contains_seafood": False,
            "is_spicy": False,
            "contains_gluten": False,
            "contains_soy": False,
            "contains_dairy": False,
            "halal": True,
            "ingredients": ["green beans", "garlic", "vegetable oil"]
        }
    ]
}

# ============================================================================
# VALIDATION LOGIC
# ============================================================================

def validate_diner(diner, menu):
    """
    Validates menu against one diner's constraints and preferences.
    Returns detailed validation result.
    """
    result = {
        "diner_id": diner["id"],
        "diner_name": diner["name"],
        "safe_to_eat": True,
        "satisfied": True,
        "hard_constraint_violations": [],
        "soft_constraint_violations": [],
        "safe_dishes": [],
        "preferred_dishes": [],
        "budget_check": None
    }

    # Check budget (hard constraint)
    if menu["total_cost_per_person"] > diner["budget_per_person"]:
        result["safe_to_eat"] = False
        result["satisfied"] = False
        result["hard_constraint_violations"].append(
            f"Budget exceeded: ${menu['total_cost_per_person']} > ${diner['budget_per_person']}"
        )
    result["budget_check"] = f"${menu['total_cost_per_person']} ≤ ${diner['budget_per_person']}"

    # Analyze each dish
    for dish in menu["dishes"]:
        dish_safe = True
        dish_violations = []

        # Check allergies (hard constraint)
        for allergen in diner["allergies"]:
            if allergen.lower() in [a.lower() for a in dish["allergens"]]:
                dish_safe = False
                dish_violations.append(f"Contains allergen: {allergen}")

        # Check dietary restrictions (hard constraint)
        for restriction in diner["dietary_restrictions"]:
            if restriction == "vegetarian" and (dish["contains_meat"] or dish["contains_seafood"]):
                dish_safe = False
                dish_violations.append(f"Not vegetarian")
            elif restriction == "vegan" and (dish["contains_meat"] or dish["contains_seafood"] or
                                            dish["contains_dairy"] or "egg" in dish["ingredients"]):
                dish_safe = False
                dish_violations.append(f"Not vegan")
            elif restriction == "halal" and not dish["halal"]:
                dish_safe = False
                dish_violations.append(f"Not halal")
            elif restriction == "pescatarian" and dish["contains_meat"]:
                dish_safe = False
                dish_violations.append(f"Contains meat (not pescatarian)")

        if dish_safe:
            result["safe_dishes"].append(dish["name"])

            # Check soft constraints (preferences)
            dish_preferred = True

            # Check cuisine preferences
            if dish["cuisine"] in diner["cuisine_preferences"]:
                pass  # Positive match

            # Check dislikes
            for dislike in diner["dislikes"]:
                dislike_lower = dislike.lower()
                dish_name_lower = dish["name"].lower()
                dish_ingredients_lower = [i.lower() for i in dish["ingredients"]]

                if (dislike_lower in dish_name_lower or
                    any(dislike_lower in ing for ing in dish_ingredients_lower)):
                    dish_preferred = False
                    result["soft_constraint_violations"].append(
                        f"{dish['name']}: contains disliked item '{dislike}'"
                    )

                # Special cases
                if dislike == "spicy food" and dish["is_spicy"]:
                    dish_preferred = False
                    result["soft_constraint_violations"].append(
                        f"{dish['name']}: is spicy"
                    )

            if dish_preferred:
                result["preferred_dishes"].append(dish["name"])
        else:
            result["safe_to_eat"] = False
            result["satisfied"] = False
            for violation in dish_violations:
                result["hard_constraint_violations"].append(f"{dish['name']}: {violation}")

    # If no safe dishes, not safe to eat
    if len(result["safe_dishes"]) == 0:
        result["safe_to_eat"] = False
        result["satisfied"] = False
        result["hard_constraint_violations"].append("No safe dishes available")

    # Satisfied requires at least some preferred dishes
    if len(result["preferred_dishes"]) < 3:  # Threshold: at least 3 preferred dishes
        result["satisfied"] = False
        if len(result["soft_constraint_violations"]) == 0:
            result["soft_constraint_violations"].append(
                f"Only {len(result['preferred_dishes'])} preferred dishes (want ≥3)"
            )

    return result

def calculate_fairness_score(validation_results):
    """
    Calculates a 0-100 fairness score based on validation results.

    Scoring:
    - All diners safe to eat: 50 points baseline
    - Each satisfied diner: +5 points (max 50)
    - Penalty for hard constraint violations: -10 per violation
    - Penalty for soft constraint violations: -2 per violation
    """
    total_diners = len(validation_results)
    safe_count = sum(1 for r in validation_results if r["safe_to_eat"])
    satisfied_count = sum(1 for r in validation_results if r["satisfied"])

    hard_violations = sum(len(r["hard_constraint_violations"]) for r in validation_results)
    soft_violations = sum(len(r["soft_constraint_violations"]) for r in validation_results)

    # Base score: safety
    if safe_count == total_diners:
        score = 50
    else:
        score = (safe_count / total_diners) * 50

    # Add satisfaction bonus
    score += (satisfied_count / total_diners) * 50

    # Apply penalties
    score -= hard_violations * 10
    score -= soft_violations * 2

    # Clamp to 0-100
    score = max(0, min(100, score))

    return {
        "score": round(score, 1),
        "safe_count": safe_count,
        "satisfied_count": satisfied_count,
        "total_diners": total_diners,
        "hard_violations": hard_violations,
        "soft_violations": soft_violations
    }

# ============================================================================
# MAIN EXECUTION
# ============================================================================

def main():
    print("=" * 80)
    print("CHINESE-STYLE SHARED DINNER FAIRNESS ANALYSIS")
    print("=" * 80)
    print()

    # 1. Display preference table
    preference_data = []
    for diner in diners:
        preference_data.append({
            "ID": diner["id"],
            "Name": diner["name"],
            "Allergies": ", ".join(diner["allergies"]) if diner["allergies"] else "None",
            "Dietary Restrictions": ", ".join(diner["dietary_restrictions"]) if diner["dietary_restrictions"] else "None",
            "Budget ($/person)": diner["budget_per_person"],
            "Cuisine Preferences": ", ".join(diner["cuisine_preferences"]),
            "Dislikes": ", ".join(diner["dislikes"])
        })

    df_preferences = pd.DataFrame(preference_data)
    print("DINER PREFERENCE TABLE")
    print("-" * 80)
    print(df_preferences.to_string(index=False))
    print("\n")

    # Export preferences
    df_preferences.to_csv("diner_preferences.csv", index=False)
    print("✓ Exported: diner_preferences.csv\n")

    # 2. Display menu
    print("=" * 80)
    print("AI-GENERATED MENU")
    print("=" * 80)
    print(f"Cost per person: ${menu['total_cost_per_person']}\n")

    menu_data = []
    for dish in menu["dishes"]:
        menu_data.append({
            "Dish": dish["name"],
            "Cuisine": dish["cuisine"],
            "Price": f"${dish['price']}",
            "Serves": dish["serves"],
            "Allergens": ", ".join(dish["allergens"]) if dish["allergens"] else "None",
            "Dietary": f"{'Meat' if dish['contains_meat'] else ''}{'Seafood' if dish['contains_seafood'] else ''}{'Veg' if not dish['contains_meat'] and not dish['contains_seafood'] else ''}"
        })

    df_menu = pd.DataFrame(menu_data)
    print(df_menu.to_string(index=False))
    print("\n")

    # 3. Validate each diner
    print("=" * 80)
    print("DINER-BY-DINER VALIDATION")
    print("=" * 80)
    print()

    validation_results = []
    for diner in diners:
        result = validate_diner(diner, menu)
        validation_results.append(result)

        print(f"{'─' * 80}")
        print(f"DINER #{diner['id']}: {diner['name']}")
        print(f"{'─' * 80}")
        print(f"Budget Check: {result['budget_check']}")
        print(f"Safe to Eat: {'✓ YES' if result['safe_to_eat'] else '✗ NO'}")
        print(f"Satisfied: {'✓ YES' if result['satisfied'] else '✗ NO'}")
        print()

        if result["hard_constraint_violations"]:
            print("HARD CONSTRAINT VIOLATIONS:")
            for violation in result["hard_constraint_violations"]:
                print(f"  ✗ {violation}")
            print()

        if result["soft_constraint_violations"]:
            print("SOFT CONSTRAINT VIOLATIONS (dislikes/preferences):")
            for violation in result["soft_constraint_violations"]:
                print(f"  ⚠ {violation}")
            print()

        print(f"Safe Dishes ({len(result['safe_dishes'])}): {', '.join(result['safe_dishes']) if result['safe_dishes'] else 'NONE'}")
        print(f"Preferred Dishes ({len(result['preferred_dishes'])}): {', '.join(result['preferred_dishes']) if result['preferred_dishes'] else 'NONE'}")
        print()

    # 4. Calculate fairness score
    print("=" * 80)
    print("FAIRNESS EVALUATION")
    print("=" * 80)
    print()

    fairness = calculate_fairness_score(validation_results)

    print(f"Safe to Eat: {fairness['safe_count']}/{fairness['total_diners']} diners")
    print(f"Satisfied: {fairness['satisfied_count']}/{fairness['total_diners']} diners")
    print(f"Hard Constraint Violations: {fairness['hard_violations']}")
    print(f"Soft Constraint Violations: {fairness['soft_violations']}")
    print()
    print(f"{'═' * 80}")
    print(f"FAIRNESS SCORE: {fairness['score']}/100")
    print(f"{'═' * 80}")
    print()

    # 5. Nobody is disadvantaged?
    nobody_disadvantaged = fairness['safe_count'] == fairness['total_diners']
    print(f"Does this menu achieve \"nobody is disadvantaged\"?")
    print(f"{'✓ YES' if nobody_disadvantaged else '✗ NO'} - All diners {'can' if nobody_disadvantaged else 'CANNOT'} safely eat from this menu.")
    print()

    if not nobody_disadvantaged:
        print("Diners who are disadvantaged:")
        for result in validation_results:
            if not result["safe_to_eat"]:
                print(f"  - {result['diner_name']}: {', '.join(result['hard_constraint_violations'])}")
        print()

    # 6. Export full results
    evaluation_data = {
        "timestamp": datetime.now().isoformat(),
        "menu": menu,
        "diners": diners,
        "validation_results": validation_results,
        "fairness_score": fairness,
        "nobody_disadvantaged": nobody_disadvantaged
    }

    with open("menu_evaluation_results.json", "w") as f:
        json.dump(evaluation_data, f, indent=2)

    print("✓ Exported: menu_evaluation_results.json")

    # 7. Create summary CSV
    summary_data = []
    for result in validation_results:
        summary_data.append({
            "Diner": result["diner_name"],
            "Safe to Eat": "Yes" if result["safe_to_eat"] else "No",
            "Satisfied": "Yes" if result["satisfied"] else "No",
            "Hard Violations": len(result["hard_constraint_violations"]),
            "Soft Violations": len(result["soft_constraint_violations"]),
            "Safe Dishes": len(result["safe_dishes"]),
            "Preferred Dishes": len(result["preferred_dishes"])
        })

    df_summary = pd.DataFrame(summary_data)
    df_summary.to_csv("validation_summary.csv", index=False)
    print("✓ Exported: validation_summary.csv")
    print()

if __name__ == "__main__":
    main()
