"""
💀 PERSONALISATION SYSTEM - ORGAN #2 💀

WHAT IT DOES:
Takes customer + menu data → analyzes behavior → generates hyper-personalized messages
Supports batch (>10 customers) and real-time (≤10) modes
Learns from feedback to improve recommendations over time

FEATURES:
✅ Universal data source support (JSON, CSV, API, files)
✅ Smart mode detection (batch vs real-time)
✅ Dietary preference analysis
✅ AI-powered recommendations
✅ Personalized message generation
✅ Feedback loop learning
✅ Manifest generation with full run tracking

BASED ON: N8N Pizza Express workflow prototype
INHERITS FROM: SystemBase (full tool injection, universal interface)
"""

import asyncio
import time
import re
from typing import Dict, Any, List, Optional, Union, Tuple
from pathlib import Path
from datetime import datetime, timedelta
from .base import SystemBase, StageResult


class PersonalisationSystem(SystemBase):
    """
    💀 ORGAN #2: PERSONALISATION SYSTEM 💀

    Customer-focused personalization engine that:
    - Analyzes customer behavior and preferences
    - Matches customers to menu items
    - Generates AI-powered recommendations
    - Creates personalized WhatsApp messages
    - Learns from customer feedback
    """

    def __init__(self, runs_dir: str = "./runs"):
        super().__init__(runs_dir)

        # Agent instances (lazy-loaded)
        self._data_agent = None
        self._brain_agent = None

        # Default configuration
        self.default_config = {
            "batch_threshold": 10,  # >10 = batch, ≤10 = real-time
            "days_since_visit_threshold": 10,  # Filter inactive customers
            "vegetarian_threshold": 0.9,  # 90%+ veg orders = vegetarian
            "ai_provider": "deepseek",  # Brain provider
            "language": "en",  # English only (v1)
            "message_format": "whatsapp",  # WhatsApp formatting
            "dry_run": False,
            "enable_feedback_learning": True,
        }

        # Message templates (from N8N)
        self.message_templates = {
            "intros": [
                "Hey {name}! Long time no see 🍕",
                "We've missed your taste buds!",
                "Craving something cheesy?",
                "Your favorite flavors are calling!",
                "Ready for another delicious adventure?"
            ],
            "outros": [
                "Your slice is waiting 👉",
                "Come treat yourself — you deserve it 😋",
                "We've saved your favorite seat.",
                "Can't wait to serve you!",
                "See you soon!"
            ]
        }

    # ========== 💀 SHADOW MONARCH INTERFACE 💀 ==========

    async def _run_async(self, customer_data: Any, menu_data: Any = None, **kwargs):
        """
        Core async implementation (follows DataSystem pattern)

        Args:
            customer_data: Customer records (JSON, CSV, file path, URL, list, dict)
            menu_data: Menu items (JSON, CSV, file path, URL, list, dict)
            **kwargs: Configuration overrides
        """
        run_name = kwargs.get('run_name')
        if not run_name:
            if isinstance(customer_data, str):
                if not customer_data.startswith('http'):
                    run_name = Path(customer_data).name
                else:
                    run_name = customer_data.split('/')[-1] or "web-customers"
            else:
                run_name = None

        dry_run = kwargs.get('dry_run', self.default_config['dry_run'])
        resume = kwargs.get('resume', False)
        stream = kwargs.get('stream', False)
        batch_threshold = kwargs.get('batch_threshold', self.default_config['batch_threshold'])
        days_threshold = kwargs.get('days_since_visit_threshold', self.default_config['days_since_visit_threshold'])
        veg_threshold = kwargs.get('vegetarian_threshold', self.default_config['vegetarian_threshold'])
        enable_learning = kwargs.get('enable_feedback_learning', self.default_config['enable_feedback_learning'])

        self._init_run(run_name, resume=resume)

        if stream:
            self._set_streaming(True)

        try:
            print("💀 Loading customer data...")
            customers = await self._load_input(customer_data)
            self._save_stage("input_customers", "01_customers.json", customers)

            print("💀 Loading menu data...")
            menu = await self._load_input(menu_data) if menu_data else []
            self._save_stage("input_menu", "01_menu.json", menu)

            # Detect mode
            mode = "batch" if len(customers) > batch_threshold else "realtime"
            print(f"💀 Mode: {mode.upper()} ({len(customers)} customers)")

            if stream:
                result = await self._run_pipeline_streaming(
                    customers, menu, dry_run, days_threshold, veg_threshold, enable_learning, mode
                )
            else:
                result = await self._run_pipeline(
                    customers, menu, dry_run, days_threshold, veg_threshold, enable_learning, mode
                )

            return result

        except Exception as e:
            print(f"\n❌ RUN FAILED: {e}")
            import traceback
            traceback.print_exc()
            manifest = self._generate_manifest(status="failed")
            return manifest.to_dict()
        finally:
            if stream:
                self._set_streaming(False)

    # ========== INPUT LOADING ==========

    async def _load_input(self, data: Any) -> List[Dict]:
        """Universal input loader (supports all data sources)"""
        if data is None:
            return []

        if isinstance(data, str):
            if data.startswith('http'):
                print(f"   🌐 Fetching from: {data}")
                agent = self._get_data_agent()
                return agent.web.get.data(data)
            else:
                print(f"   📁 Loading file: {data}")
                agent = self._get_data_agent()
                return agent.files.load(data)
        elif isinstance(data, list):
            return data
        elif isinstance(data, dict):
            # Try to extract from wrapper keys
            for key in ['customers', 'data', 'items', 'records', 'users']:
                if key in data and isinstance(data[key], list):
                    return data[key]
            return [data]
        else:
            return [data] if data else []

    # ========== AGENT LOADING ==========

    def _get_data_agent(self):
        """Get data agent for file/web operations"""
        if self._data_agent is None:
            from monarchs import summon
            self._data_agent = summon("data")
        return self._data_agent

    def _get_brain_agent(self):
        """Get brain agent for AI operations"""
        if self._brain_agent is None:
            try:
                from brain import get_brain
                provider = self.default_config['ai_provider']
                self._brain_agent = get_brain(provider)
            except Exception as e:
                print(f"⚠️  Brain loading failed: {e}")
                self._brain_agent = None
        return self._brain_agent

    # ========== PIPELINE EXECUTION ==========

    async def _run_pipeline(
        self,
        customers: List[Dict],
        menu: List[Dict],
        dry_run: bool,
        days_threshold: int,
        veg_threshold: float,
        enable_learning: bool,
        mode: str
    ) -> Dict:
        """
        💀 8-STAGE PERSONALISATION PIPELINE 💀

        Stage 1: Load & Validate
        Stage 2: Customer Segmentation
        Stage 3: Menu Matching
        Stage 4: AI Recommendations
        Stage 5: Message Generation
        Stage 6: Delivery Preparation
        Stage 7: Output
        Stage 8: Manifest
        """

        # Stage 1: Load & Validate
        valid_customers, valid_menu = await self._stage_load_validate(customers, menu)

        # Stage 2: Customer Segmentation
        segmented = await self._stage_segment_customers(valid_customers, days_threshold, veg_threshold)

        # Stage 3: Menu Matching
        matched = await self._stage_match_menu(segmented, valid_menu)

        # Stage 4: AI Recommendations
        recommendations = await self._stage_recommend(matched, dry_run)

        # Stage 5: Message Generation
        messages = await self._stage_generate_messages(recommendations, mode)

        # Stage 6: Delivery Preparation
        prepared = await self._stage_prepare_delivery(messages)

        # Stage 7: Output
        outputs = await self._stage_output(prepared)

        # Stage 8: Manifest
        manifest = self._generate_manifest(status="completed")

        return manifest.to_dict()

    async def _run_pipeline_streaming(
        self,
        customers: List[Dict],
        menu: List[Dict],
        dry_run: bool,
        days_threshold: int,
        veg_threshold: float,
        enable_learning: bool,
        mode: str
    ) -> Dict:
        """Streaming pipeline with real-time updates"""

        # Stage 1
        self._update_stream({"stage": "load_validate", "status": "running"})
        valid_customers, valid_menu = await self._stage_load_validate(customers, menu)
        self._update_stream({"stage": "load_validate", "status": "complete", "customers": len(valid_customers), "menu": len(valid_menu)})

        # Stage 2
        self._update_stream({"stage": "segment", "status": "running"})
        segmented = await self._stage_segment_customers(valid_customers, days_threshold, veg_threshold)
        self._update_stream({"stage": "segment", "status": "complete", "count": len(segmented)})

        # Stage 3
        self._update_stream({"stage": "match", "status": "running"})
        matched = await self._stage_match_menu(segmented, valid_menu)
        self._update_stream({"stage": "match", "status": "complete", "count": len(matched)})

        # Stage 4
        self._update_stream({"stage": "recommend", "status": "running"})
        recommendations = await self._stage_recommend(matched, dry_run)
        self._update_stream({"stage": "recommend", "status": "complete", "count": len(recommendations)})

        # Stage 5
        self._update_stream({"stage": "generate", "status": "running"})
        messages = await self._stage_generate_messages(recommendations, mode)
        self._update_stream({"stage": "generate", "status": "complete", "count": len(messages)})

        # Stage 6
        self._update_stream({"stage": "prepare", "status": "running"})
        prepared = await self._stage_prepare_delivery(messages)
        self._update_stream({"stage": "prepare", "status": "complete", "count": len(prepared)})

        # Stage 7
        self._update_stream({"stage": "output", "status": "running"})
        outputs = await self._stage_output(prepared)
        self._update_stream({"stage": "output", "status": "complete"})

        # Stage 8
        manifest = self._generate_manifest(status="completed")
        self._update_stream({"stage": "complete", "manifest": manifest.to_dict()})

        return manifest.to_dict()

    # ========== 💀 STAGE 1: LOAD & VALIDATE 💀 ==========

    async def _stage_load_validate(self, customers: List[Dict], menu: List[Dict]) -> Tuple[List[Dict], List[Dict]]:
        """
        Stage 1: Load & Validate

        Validates customer and menu data for required fields
        """
        start = time.time()
        print("💀 Stage 1: Load & Validate...")

        try:
            valid_customers = []
            invalid_customers = []

            # Validate customers
            for customer in customers:
                if self._is_valid_customer(customer):
                    valid_customers.append(customer)
                else:
                    invalid_customers.append(customer)

            # Validate menu
            valid_menu = []
            for item in menu:
                if self._is_valid_menu_item(item):
                    valid_menu.append(item)

            # Save
            self._save_stage("valid_customers", "02_valid_customers.json", valid_customers)
            self._save_stage("invalid_customers", "02_invalid_customers.json", invalid_customers)
            self._save_stage("valid_menu", "02_valid_menu.json", valid_menu)

            result = StageResult(
                stage_name="load_validate",
                success=True,
                input_count=len(customers) + len(menu),
                output_count=len(valid_customers) + len(valid_menu),
                duration=time.time() - start,
                output_path=self.run_dir / "02_valid_customers.json",
                metadata={
                    "valid_customers": len(valid_customers),
                    "invalid_customers": len(invalid_customers),
                    "valid_menu": len(valid_menu)
                }
            )
            self._record_stage(result)

            print(f"   💾 Saved: {result.output_path}")
            print(f"   ✅ Valid: {len(valid_customers)} customers, {len(valid_menu)} menu items ({result.duration:.2f}s)")
            if invalid_customers:
                print(f"   ⚠️  Rejected: {len(invalid_customers)} invalid customers")

            return valid_customers, valid_menu

        except Exception as e:
            print(f"   ❌ Validation failed: {e}")
            raise

    def _is_valid_customer(self, customer: Dict) -> bool:
        """Validate customer has required fields"""
        if not isinstance(customer, dict):
            return False

        # Must have: name, phone
        required = ['name', 'phone']
        for field in required:
            # Try multiple field name variations
            field_variations = [field, field.lower(), field.upper(), field.replace('_', ' ').title()]
            found = False
            for variation in field_variations:
                if variation in customer and customer[variation]:
                    found = True
                    break
            if not found:
                return False

        # Phone validation (basic)
        phone = str(customer.get('phone') or customer.get('Phone Number') or customer.get('Phone') or '')
        if len(phone.replace(' ', '').replace('-', '')) < 10:
            return False

        return True

    def _is_valid_menu_item(self, item: Dict) -> bool:
        """Validate menu item has required fields"""
        if not isinstance(item, dict):
            return False

        # Must have: name or Item
        if 'name' not in item and 'Item' not in item and 'item' not in item:
            return False

        return True

    # ========== 💀 STAGE 2: CUSTOMER SEGMENTATION 💀 ==========

    async def _stage_segment_customers(
        self,
        customers: List[Dict],
        days_threshold: int,
        veg_threshold: float
    ) -> List[Dict]:
        """
        Stage 2: Customer Segmentation

        Segments customers by:
        - Activity (days since last visit)
        - Diet preference (vegetarian vs non-vegetarian)
        - Order frequency
        """
        start = time.time()
        print("💀 Stage 2: Customer Segmentation...")

        try:
            segmented = []

            for customer in customers:
                # Calculate days since last visit
                days_since_visit = self._calculate_days_since_visit(customer)

                # Filter: Only customers who visited >X days ago
                if days_since_visit <= days_threshold:
                    continue

                # Calculate vegetarian percentage
                veg_percentage = self._calculate_veg_percentage(customer)

                # Determine segment
                if veg_percentage >= veg_threshold:
                    segment = "vegetarian"
                elif veg_percentage > 0:
                    segment = "mixed"
                else:
                    segment = "non_vegetarian"

                # Enrich customer with segment data
                enriched = {
                    **customer,
                    'days_since_visit': days_since_visit,
                    'veg_percentage': veg_percentage,
                    'segment': segment,
                    'order_count': len(customer.get('order_history') or customer.get('Order History') or [])
                }

                segmented.append(enriched)

            # Save
            output_path = self._save_stage("segmented", "03_segmented.json", segmented)

            result = StageResult(
                stage_name="segment",
                success=True,
                input_count=len(customers),
                output_count=len(segmented),
                duration=time.time() - start,
                output_path=output_path,
                metadata={
                    "filtered_out": len(customers) - len(segmented),
                    "vegetarian": sum(1 for c in segmented if c['segment'] == 'vegetarian'),
                    "non_vegetarian": sum(1 for c in segmented if c['segment'] == 'non_vegetarian'),
                    "mixed": sum(1 for c in segmented if c['segment'] == 'mixed')
                }
            )
            self._record_stage(result)

            print(f"   💾 Saved: {output_path}")
            print(f"   ✅ Segmented: {len(segmented)} active customers ({result.duration:.2f}s)")
            print(f"      🌱 Vegetarian: {result.metadata['vegetarian']}")
            print(f"      🍕 Non-vegetarian: {result.metadata['non_vegetarian']}")
            print(f"      🔀 Mixed: {result.metadata['mixed']}")

            return segmented

        except Exception as e:
            print(f"   ❌ Segmentation failed: {e}")
            raise

    def _calculate_days_since_visit(self, customer: Dict) -> int:
        """Calculate days since last visit"""
        # Try multiple field variations
        days_field = (customer.get('days_since_last_order') or
                     customer.get('Days since last order') or
                     customer.get('days_since_visit') or
                     customer.get('Days Since Visit'))

        if days_field is not None:
            try:
                return int(days_field)
            except:
                pass

        # Calculate from order history
        order_history = customer.get('order_history') or customer.get('Order History') or []
        if not order_history:
            return 999  # No orders = very old

        # Get last order date
        try:
            last_order = order_history[-1]
            if isinstance(last_order, dict) and 'date' in last_order:
                last_date = datetime.fromisoformat(last_order['date'].replace('Z', '+00:00'))
                days = (datetime.now() - last_date).days
                return days
            else:
                return 999
        except:
            return 999

    def _calculate_veg_percentage(self, customer: Dict) -> float:
        """Calculate percentage of vegetarian orders"""
        # Try direct field first
        veg_pct_field = customer.get('veg_percentage') or customer.get('Veg %') or customer.get('veg %')
        if veg_pct_field is not None:
            try:
                return float(veg_pct_field)
            except:
                pass

        # Check IsVegetarian field
        is_veg_field = customer.get('IsVegetarian') or customer.get('is_vegetarian')
        if is_veg_field:
            if isinstance(is_veg_field, bool):
                return 1.0 if is_veg_field else 0.0
            elif isinstance(is_veg_field, str):
                return 1.0 if is_veg_field.lower() in ['yes', 'true', '1'] else 0.0

        # Calculate from order history
        order_history = customer.get('order_history') or customer.get('Order History') or []
        if not order_history:
            return 0.0

        veg_count = 0
        total_count = len(order_history)

        for order in order_history:
            if isinstance(order, dict):
                items = order.get('items', [])
                for item in items:
                    # Check if item is vegetarian
                    if isinstance(item, dict):
                        category = item.get('category', '').lower()
                        name = item.get('name', '').lower()
                        if 'veg' in category or 'veg' in name or 'vegetarian' in category:
                            veg_count += 1
                    elif isinstance(item, str):
                        if 'veg' in item.lower():
                            veg_count += 1

        return veg_count / total_count if total_count > 0 else 0.0

    # ========== 💀 STAGE 3: MENU MATCHING 💀 ==========

    async def _stage_match_menu(self, customers: List[Dict], menu: List[Dict]) -> List[Dict]:
        """
        Stage 3: Menu Matching

        Match customers to relevant menu items based on their preferences
        """
        start = time.time()
        print("💀 Stage 3: Menu Matching...")

        try:
            matched = []

            for customer in customers:
                segment = customer.get('segment', 'mixed')

                # Filter menu by segment
                relevant_menu = []
                for item in menu:
                    category = item.get('category', item.get('Category', '')).lower()
                    name = item.get('name', item.get('Item', item.get('item', ''))).lower()

                    if segment == 'vegetarian':
                        if 'veg' in category or 'veg' in name or 'vegetarian' in category:
                            relevant_menu.append(item)
                    elif segment == 'non_vegetarian':
                        if 'non-veg' in category or 'chicken' in name or 'meat' in name:
                            relevant_menu.append(item)
                    else:
                        relevant_menu.append(item)

                # Enrich with matched menu
                enriched = {
                    **customer,
                    'matched_menu': relevant_menu[:5]  # Top 5 matches
                }

                matched.append(enriched)

            # Save
            output_path = self._save_stage("matched", "04_matched.json", matched)

            result = StageResult(
                stage_name="match_menu",
                success=True,
                input_count=len(customers),
                output_count=len(matched),
                duration=time.time() - start,
                output_path=output_path
            )
            self._record_stage(result)

            print(f"   💾 Saved: {output_path}")
            print(f"   ✅ Matched: {len(matched)} customers to menu ({result.duration:.2f}s)")

            return matched

        except Exception as e:
            print(f"   ❌ Menu matching failed: {e}")
            raise

    # ========== 💀 STAGE 4: AI RECOMMENDATIONS 💀 ==========

    async def _stage_recommend(self, customers: List[Dict], dry_run: bool) -> List[Dict]:
        """
        Stage 4: AI Recommendations

        Use AI to generate personalized dish recommendations
        """
        start = time.time()
        print("💀 Stage 4: AI Recommendations...")

        try:
            if dry_run:
                print("   ⚠️  Dry run - using fallback recommendations")
                recommendations = self._fallback_recommendations(customers)
            else:
                recommendations = await self._ai_recommendations(customers)

            # Save
            output_path = self._save_stage("recommendations", "05_recommendations.json", recommendations)

            result = StageResult(
                stage_name="recommend",
                success=True,
                input_count=len(customers),
                output_count=len(recommendations),
                duration=time.time() - start,
                output_path=output_path,
                metadata={"dry_run": dry_run}
            )
            self._record_stage(result)

            print(f"   💾 Saved: {output_path}")
            print(f"   ✅ Recommendations: {len(recommendations)} generated ({result.duration:.2f}s)")

            return recommendations

        except Exception as e:
            print(f"   ❌ Recommendations failed: {e}")
            # Fallback
            return self._fallback_recommendations(customers)

    async def _ai_recommendations(self, customers: List[Dict]) -> List[Dict]:
        """Generate AI-powered recommendations"""
        brain = self._get_brain_agent()
        if not brain:
            return self._fallback_recommendations(customers)

        recommendations = []

        for customer in customers:
            try:
                # Build prompt
                prompt = self._build_recommendation_prompt(customer)

                # Get AI recommendation (using proper brain interface)
                try:
                    response = await brain.think(prompt)
                except AttributeError:
                    # Fallback if think doesn't exist
                    response = brain._think(
                        action="recommend_menu_items",
                        context={"prompt": prompt},
                        user_message=prompt
                    )

                # Parse recommendation
                recommended_dish = self._parse_recommendation(response, customer)

                # Enrich
                enriched = {
                    **customer,
                    'recommended_dish': recommended_dish,
                    'recommendation_source': 'ai'
                }

                recommendations.append(enriched)

            except Exception as e:
                print(f"   ⚠️  AI failed for {customer.get('name', 'Unknown')}: {e}")
                # Fallback for this customer
                enriched = {
                    **customer,
                    'recommended_dish': self._fallback_dish(customer),
                    'recommendation_source': 'fallback'
                }
                recommendations.append(enriched)

        return recommendations

    def _build_recommendation_prompt(self, customer: Dict) -> str:
        """Build AI prompt for recommendation (from N8N logic)"""
        name = customer.get('name') or customer.get('Customer Name', 'Customer')
        segment = customer.get('segment', 'mixed')
        order_count = customer.get('order_count', 0)
        veg_percentage = customer.get('veg_percentage', 0)
        matched_menu = customer.get('matched_menu', [])

        # Get last order
        order_history = customer.get('order_history') or customer.get('Order History') or []
        last_order = "a previous favorite"
        if order_history:
            last = order_history[-1]
            if isinstance(last, dict):
                last_order = last.get('items', [{}])[0].get('name', last_order) if last.get('items') else last_order
            elif isinstance(last, str):
                last_order = last

        menu_names = [item.get('name', item.get('Item', 'Unknown')) for item in matched_menu[:5]]

        prompt = f"""You are a real staff member at a restaurant. You know every customer and their taste.

Based on their last order ("{last_order}"), recommend 1-2 items from the menu below that they'd love — focus on **similar flavor, texture, or ingredients**.

Menu:
{', '.join(menu_names)}

Recommended items:"""

        return prompt

    def _parse_recommendation(self, response: str, customer: Dict) -> str:
        """Parse AI response to extract dish name"""
        # Simple parsing - take first line
        dish = response.strip().split('\n')[0]
        dish = dish.strip('"\'.,!?•-*')

        # Validate against matched menu
        matched_menu = customer.get('matched_menu', [])
        for item in matched_menu:
            item_name = item.get('name', item.get('Item', ''))
            if item_name.lower() in dish.lower():
                return item_name

        # Fallback
        return dish if dish else self._fallback_dish(customer)

    def _fallback_recommendations(self, customers: List[Dict]) -> List[Dict]:
        """Fallback recommendations without AI"""
        recommendations = []

        for customer in customers:
            enriched = {
                **customer,
                'recommended_dish': self._fallback_dish(customer),
                'recommendation_source': 'fallback'
            }
            recommendations.append(enriched)

        return recommendations

    def _fallback_dish(self, customer: Dict) -> str:
        """Get fallback dish based on segment"""
        segment = customer.get('segment', 'mixed')
        matched_menu = customer.get('matched_menu', [])

        if matched_menu:
            return matched_menu[0].get('name', matched_menu[0].get('Item', 'Special Pizza'))

        if segment == 'vegetarian':
            return "Margherita Pizza"
        elif segment == 'non_vegetarian':
            return "Pepperoni Pizza"
        else:
            return "Chef's Special"

    # ========== 💀 STAGE 5: MESSAGE GENERATION 💀 ==========

    async def _stage_generate_messages(self, recommendations: List[Dict], mode: str) -> List[Dict]:
        """
        Stage 5: Message Generation

        Generate personalized WhatsApp messages using N8N templates
        """
        start = time.time()
        print("💀 Stage 5: Message Generation...")

        try:
            messages = []

            for customer in recommendations:
                # Generate message using randomized templates (from N8N)
                message_text = self._generate_message(customer)

                # Format for WhatsApp
                whatsapp_formatted = self._format_whatsapp(message_text, customer)

                # Enrich
                enriched = {
                    **customer,
                    'message': message_text,
                    'whatsapp_message': whatsapp_formatted,
                    'message_generated_at': datetime.now().isoformat(),
                    'mode': mode
                }

                messages.append(enriched)

            # Save
            output_path = self._save_stage("messages", "06_messages.json", messages)

            result = StageResult(
                stage_name="generate_messages",
                success=True,
                input_count=len(recommendations),
                output_count=len(messages),
                duration=time.time() - start,
                output_path=output_path,
                metadata={"mode": mode}
            )
            self._record_stage(result)

            print(f"   💾 Saved: {output_path}")
            print(f"   ✅ Messages: {len(messages)} generated ({result.duration:.2f}s)")

            return messages

        except Exception as e:
            print(f"   ❌ Message generation failed: {e}")
            raise

    def _generate_message(self, customer: Dict) -> str:
        """Generate personalized message with randomized intro/outro (N8N pattern)"""
        import random

        name = customer.get('name') or customer.get('Customer Name', 'Friend')
        dish = customer.get('recommended_dish', 'Special')

        # Random intro (N8N pattern)
        intro = random.choice(self.message_templates['intros']).format(name=name)

        # Body with recommendation
        body = f"Based on your last order, we think you'll love our {dish}!"

        # Random outro (N8N pattern)
        outro = random.choice(self.message_templates['outros'])

        # Combine
        message = f"{intro} {body} {outro}"

        return message

    def _format_whatsapp(self, message: str, customer: Dict) -> Dict:
        """Format message for WhatsApp API"""
        phone = customer.get('phone') or customer.get('Phone Number', '')

        # Clean phone (remove non-digits)
        clean_phone = re.sub(r'\D', '', str(phone))

        return {
            'to': clean_phone,
            'body': message,
            'platform': 'whatsapp'
        }

    # ========== 💀 STAGE 6: DELIVERY PREPARATION 💀 ==========

    async def _stage_prepare_delivery(self, messages: List[Dict]) -> List[Dict]:
        """
        Stage 6: Delivery Preparation

        Prepare messages for delivery (but DON'T send them)
        This follows the user requirement: PREPARE ONLY, don't send
        """
        start = time.time()
        print("💀 Stage 6: Delivery Preparation...")

        try:
            prepared = []

            for message in messages:
                # Add delivery metadata
                enriched = {
                    **message,
                    'prepared_at': datetime.now().isoformat(),
                    'delivery_status': 'prepared',
                    'send_ready': True
                }

                prepared.append(enriched)

            # Save
            output_path = self._save_stage("prepared", "07_prepared.json", prepared)

            result = StageResult(
                stage_name="prepare_delivery",
                success=True,
                input_count=len(messages),
                output_count=len(prepared),
                duration=time.time() - start,
                output_path=output_path
            )
            self._record_stage(result)

            print(f"   💾 Saved: {output_path}")
            print(f"   ✅ Prepared: {len(prepared)} messages ready for delivery ({result.duration:.2f}s)")
            print(f"   ⚠️  Messages are PREPARED only - not sent!")

            return prepared

        except Exception as e:
            print(f"   ❌ Preparation failed: {e}")
            raise

    # ========== 💀 STAGE 7: OUTPUT 💀 ==========

    async def _stage_output(self, prepared: List[Dict]) -> Dict:
        """
        Stage 7: Output

        Export prepared messages in multiple formats (JSON, CSV, delivery-ready)
        """
        start = time.time()
        print("💀 Stage 7: Output...")

        try:
            # Clean output (remove internal fields)
            clean_output = []
            for record in prepared:
                clean = {
                    'customer_name': record.get('name') or record.get('Customer Name'),
                    'customer_phone': record.get('phone') or record.get('Phone Number'),
                    'segment': record.get('segment'),
                    'recommended_dish': record.get('recommended_dish'),
                    'message': record.get('message'),
                    'whatsapp_formatted': record.get('whatsapp_message'),
                    'delivery_status': record.get('delivery_status'),
                    'prepared_at': record.get('prepared_at')
                }
                clean_output.append(clean)

            # Save JSON
            json_path = self._save_stage("final_json", "08_final.json", clean_output)

            # Save CSV
            csv_data = self._to_csv(clean_output)
            csv_path = self._save_stage("final_csv", "08_final.csv", csv_data)

            # Save delivery-ready format
            delivery_ready = [r.get('whatsapp_message') for r in prepared]
            delivery_path = self._save_stage("delivery_ready", "08_delivery_ready.json", delivery_ready)

            outputs = {
                "json": json_path,
                "csv": csv_path,
                "delivery_ready": delivery_path,
                "count": len(clean_output)
            }

            result = StageResult(
                stage_name="output",
                success=True,
                input_count=len(prepared),
                output_count=len(clean_output),
                duration=time.time() - start,
                output_path=json_path,
                metadata={"formats": ["json", "csv", "delivery_ready"]}
            )
            self._record_stage(result)

            print(f"   💾 Saved JSON: {json_path}")
            print(f"   💾 Saved CSV: {csv_path}")
            print(f"   💾 Saved Delivery: {delivery_path}")
            print(f"   ✅ Exported {len(clean_output)} messages ({result.duration:.2f}s)")

            return outputs

        except Exception as e:
            print(f"   ❌ Output failed: {e}")
            raise

    def _to_csv(self, data: List[Dict]) -> str:
        """Convert to CSV"""
        if not data:
            return ""

        keys = set()
        for item in data:
            if isinstance(item, dict):
                keys.update(item.keys())

        keys = sorted(keys)
        lines = [','.join(keys)]

        for item in data:
            if isinstance(item, dict):
                values = []
                for k in keys:
                    val = item.get(k, '')
                    # Handle nested dicts/lists
                    if isinstance(val, (dict, list)):
                        val = str(val).replace(',', ';')
                    values.append(f'"{val}"')  # Quote values for CSV safety
                lines.append(','.join(values))

        return '\n'.join(lines)
