"""
Routines command handler - bot-side hooks for routine management
"""

from bot.command_registry import register_module
import ai.parser as ai_parser


async def handle_routine(message, session, parsed):
    action = parsed.get("action", "unknown")
    token = session["token"]
    user_uuid = session["user_uuid"]

    if action == "list":
        resp, status = api_request("get", "/api/routines", token)
        if status == 200:
            routines = resp if isinstance(resp, list) else []
            if not routines:
                await message.channel.send("You don't have any routines yet.")
            else:
                lines = [f"- **{r['name']}**: {r.get('description', 'No description')}" for r in routines]
                await message.channel.send("**Your routines:**\n" + "\n".join(lines))
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to fetch routines')}")

    elif action == "create":
        name = parsed.get("name")
        description = parsed.get("description")
        needs_confirmation = parsed.get("needs_confirmation", False)
        confirmation_prompt = parsed.get("confirmation_prompt")

        if not name:
            await message.channel.send("Please provide a routine name.")
            return

        # Handle confirmation
        if needs_confirmation:
            if "pending_confirmations" not in session:
                session["pending_confirmations"] = {}
            
            confirmation_id = f"routine_create_{name}"
            session["pending_confirmations"][confirmation_id] = {
                "action": "create",
                "interaction_type": "routine",
                "name": name,
                "description": description or ""
            }
            
            await message.channel.send(
                f"{confirmation_prompt}\n\n"
                f"Reply **yes** to create it, or **no** to cancel."
            )
            return

        await _create_routine(message, token, name, description or "")

    elif action == "create_with_steps":
        name = parsed.get("name")
        steps = parsed.get("steps", [])
        description = parsed.get("description", "")
        needs_confirmation = parsed.get("needs_confirmation", True)
        confirmation_prompt = parsed.get("confirmation_prompt")

        if not name:
            await message.channel.send("Please provide a routine name.")
            return

        if not steps:
            await message.channel.send("What steps should this routine have?")
            return

        # Handle confirmation
        if needs_confirmation:
            if "pending_confirmations" not in session:
                session["pending_confirmations"] = {}
            
            confirmation_id = f"routine_create_{name}"
            session["pending_confirmations"][confirmation_id] = {
                "action": "create_with_steps",
                "interaction_type": "routine",
                "name": name,
                "description": description,
                "steps": steps
            }
            
            steps_list = "\n".join([f"{i+1}. {step}" for i, step in enumerate(steps)])
            await message.channel.send(
                f"{confirmation_prompt}\n\n"
                f"**Steps:**\n{steps_list}\n\n"
                f"Reply **yes** to create it, or **no** to cancel."
            )
            return

        await _create_routine_with_steps(message, token, name, description, steps)

    elif action == "add_steps":
        routine_name = parsed.get("routine_name")
        steps = parsed.get("steps", [])

        if not routine_name or not steps:
            await message.channel.send("Please specify the routine and steps to add.")
            return

        # Find routine by name
        routine_id, name, found = await _find_routine_by_name(message, token, None, routine_name)
        if not found:
            return

        if not routine_id:
            await message.channel.send(f"Which routine should I add steps to?")
            return

        # Add each step
        success_count = 0
        for i, step_name in enumerate(steps):
            step_data = {
                "name": step_name,
                "duration_minutes": None  # API expects minutes, not seconds
            }
            resp, status = api_request("post", f"/api/routines/{routine_id}/steps", token, step_data)
            if status == 201:
                success_count += 1

        if success_count == len(steps):
            await message.channel.send(f"✅ Added {success_count} step(s) to **{name}**!")
        else:
            await message.channel.send(f"Added {success_count} of {len(steps)} steps to **{name}**.")

    elif action == "steps":
        routine_id = parsed.get("routine_id")
        name = parsed.get("name") or parsed.get("routine_name")

        routine_id, name, found = await _find_routine_by_name(message, token, routine_id, name)
        if not found:
            return

        if not routine_id:
            await message.channel.send("Which routine's steps should I show?")
            return

        resp, status = api_request("get", f"/api/routines/{routine_id}/steps", token)
        if status == 200:
            steps = resp if isinstance(resp, list) else []
            if not steps:
                await message.channel.send(f"**{name}** has no steps yet.")
            else:
                lines = [f"{i+1}. {s['name']}" for i, s in enumerate(steps)]
                await message.channel.send(f"**Steps in {name}:**\n" + "\n".join(lines))
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to fetch steps')}")

    elif action == "schedule":
        routine_id = parsed.get("routine_id")
        name = parsed.get("name")
        days_of_week = parsed.get("days_of_week", [])
        times = parsed.get("times", [])

        routine_id, name, found = await _find_routine_by_name(message, token, routine_id, name)
        if not found:
            return

        if not routine_id:
            await message.channel.send("Which routine should I schedule?")
            return

        if not days_of_week and not times:
            await message.channel.send("When should this routine be scheduled? (e.g., 'Monday Wednesday Friday at 7am')")
            return

        # Build schedule data
        schedule_data = {}
        if days_of_week:
            schedule_data["days_of_week"] = days_of_week
        if times:
            schedule_data["times"] = times

        resp, status = api_request("put", f"/api/routines/{routine_id}/schedule", token, schedule_data)
        if status == 200:
            days_str = ', '.join(days_of_week) if days_of_week else 'daily'
            times_str = ' at ' + ', '.join(times) if times else ''
            await message.channel.send(f"📅 Scheduled **{name}** for {days_str}{times_str}")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to schedule routine')}")

    elif action == "start":
        routine_id = parsed.get("routine_id")
        name = parsed.get("name")
        
        routine_id, name, found = await _find_routine_by_name(message, token, routine_id, name)
        if not found:
            return

        if not routine_id:
            await message.channel.send("Which routine would you like to start?")
            return

        resp, status = api_request("post", f"/api/routines/{routine_id}/start", token)
        if status == 201:
            step = resp.get("current_step", {})
            total_steps = resp.get("total_steps", 0)
            current_step_num = resp.get("current_step_index", 0) + 1
            await message.channel.send(f"🚀 Started **{name}**!\n\nStep {current_step_num} of {total_steps}: **{step.get('name', 'Unknown')}**")
        elif status == 409:
            await message.channel.send(f"⚠️ You already have an active session: {resp.get('error', '')}")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to start routine')}")

    elif action == "complete":
        session_resp, _ = api_request("get", "/api/sessions/active", token)
        if "session" not in session_resp:
            await message.channel.send("No active routine session.")
            return
        session_id = session_resp["session"]["id"]
        current_step = session_resp.get("session", {}).get("current_step_index", 0) + 1
        total_steps = session_resp.get("total_steps", 0)
        
        resp, status = api_request("post", f"/api/sessions/{session_id}/complete-step", token)
        if status == 200:
            if resp.get("next_step"):
                next_step_num = current_step + 1
                await message.channel.send(f"✅ Done!\n\nStep {next_step_num} of {total_steps}: **{resp['next_step'].get('name', 'Unknown')}**")
            else:
                await message.channel.send("🎉 Completed all steps! Great job!")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to complete step')}")

    elif action == "skip":
        session_resp, _ = api_request("get", "/api/sessions/active", token)
        if "session" not in session_resp:
            await message.channel.send("No active routine session.")
            return
        session_id = session_resp["session"]["id"]
        current_step = session_resp.get("session", {}).get("current_step_index", 0) + 1
        total_steps = session_resp.get("total_steps", 0)
        
        resp, status = api_request("post", f"/api/sessions/{session_id}/skip-step", token)
        if status == 200:
            if resp.get("next_step"):
                next_step_num = current_step + 1
                await message.channel.send(f"⏭️ Skipped!\n\nStep {next_step_num} of {total_steps}: **{resp['next_step'].get('name', 'Unknown')}**")
            else:
                await message.channel.send("All steps skipped! Routine ended.")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to skip step')}")

    elif action == "cancel":
        session_resp, _ = api_request("get", "/api/sessions/active", token)
        if "session" not in session_resp:
            await message.channel.send("No active routine session to cancel.")
            return
        session_id = session_resp["session"]["id"]
        resp, status = api_request("post", f"/api/sessions/{session_id}/cancel", token)
        if status == 200:
            await message.channel.send("❌ Routine cancelled.")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to cancel')}")

    elif action == "history":
        routine_id = parsed.get("routine_id")
        name = parsed.get("name")

        routine_id, name, found = await _find_routine_by_name(message, token, routine_id, name)
        if not found:
            return

        if not routine_id:
            await message.channel.send("Which routine's history?")
            return

        resp, status = api_request("get", f"/api/routines/{routine_id}/history", token)
        if status == 200:
            sessions = resp if isinstance(resp, list) else []
            if not sessions:
                await message.channel.send("No history yet.")
            else:
                lines = [f"- {s.get('status', 'unknown')} on {s.get('created_at', '')[:10]}" for s in sessions[:5]]
                await message.channel.send(f"**Recent sessions for {name}:**\n" + "\n".join(lines))
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to fetch history')}")

    elif action == "pause":
        session_resp, _ = api_request("get", "/api/sessions/active", token)
        if "session" not in session_resp:
            await message.channel.send("No active routine session to pause.")
            return
        session_id = session_resp["session"]["id"]
        resp, status = api_request("post", f"/api/sessions/{session_id}/pause", token)
        if status == 200:
            await message.channel.send("⏸️ Routine paused. Say 'resume' when ready to continue.")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to pause')}")

    elif action == "resume":
        session_resp, _ = api_request("get", "/api/sessions/active", token)
        if "session" not in session_resp:
            await message.channel.send("You don't have a paused session.")
            return
        resp, status = api_request("post", f"/api/sessions/{session_resp['session']['id']}/resume", token)
        if status == 200:
            await message.channel.send("▶️ Resumed! Let's keep going.")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to resume')}")

    elif action == "abort":
        session_resp, _ = api_request("get", "/api/sessions/active", token)
        if "session" not in session_resp:
            await message.channel.send("No active routine session to abort.")
            return
        session_id = session_resp["session"]["id"]
        reason = parsed.get("reason", "Aborted by user")
        resp, status = api_request("post", f"/api/sessions/{session_id}/abort", token, {"reason": reason})
        if status == 200:
            await message.channel.send("🛑 Routine aborted. No worries, you can try again later!")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to abort')}")

    elif action == "note":
        session_resp, _ = api_request("get", "/api/sessions/active", token)
        if "session" not in session_resp:
            await message.channel.send("No active routine session.")
            return
        session_id = session_resp["session"]["id"]
        note = parsed.get("note")
        if not note:
            await message.channel.send("What note would you like to add?")
            return
        step_index = session_resp.get("session", {}).get("current_step_index", 0)
        resp, status = api_request("post", f"/api/sessions/{session_id}/note", token, {"step_index": step_index, "note": note})
        if status == 201:
            await message.channel.send(f"📝 Note saved: {note}")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to save note')}")

    elif action == "stats":
        routine_id = parsed.get("routine_id")
        name = parsed.get("name")

        # Check if user wants all stats or specific routine
        if not routine_id and not name:
            # Get all streaks
            resp, status = api_request("get", "/api/routines/streaks", token)
            if status == 200:
                streaks = resp if isinstance(resp, list) else []
                if not streaks:
                    await message.channel.send("No routine stats yet. Complete some routines!")
                else:
                    lines = []
                    for s in streaks:
                        routine_name = s.get('routine_name', 'Unknown')
                        current = s.get('current_streak', 0)
                        longest = s.get('longest_streak', 0)
                        lines.append(f"- **{routine_name}**: {current} day streak (best: {longest})")
                    await message.channel.send("**Your Routine Stats:**\n" + "\n".join(lines))
            else:
                await message.channel.send(f"Error: {resp.get('error', 'Failed to fetch stats')}")
            return

        routine_id, name, found = await _find_routine_by_name(message, token, routine_id, name)
        if not found:
            return

        if not routine_id:
            await message.channel.send("Which routine's stats?")
            return

        resp, status = api_request("get", f"/api/routines/{routine_id}/stats", token)
        if status == 200:
            completion = resp.get('completion_rate_percent', 0)
            completed = resp.get('completed', 0)
            total = resp.get('total_sessions', 0)
            avg_duration = resp.get('avg_duration_minutes', 0)
            
            await message.channel.send(
                f"**{resp.get('routine_name', name)} Stats:**\n"
                f"- Completion rate: {completion}%\n"
                f"- Completed: {completed}/{total} sessions\n"
                f"- Avg duration: {avg_duration} min"
            )
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to fetch stats')}")

    elif action == "streak":
        routine_id = parsed.get("routine_id")
        name = parsed.get("name")

        if routine_id or name:
            routine_id, name, found = await _find_routine_by_name(message, token, routine_id, name)
            if not found:
                return
            if routine_id:
                resp, status = api_request("get", f"/api/routines/{routine_id}/streak", token)
                if status == 200:
                    await message.channel.send(
                        f"**{resp.get('routine_name', name)}** 🔥\n"
                        f"Current streak: {resp.get('current_streak', 0)} days\n"
                        f"Longest streak: {resp.get('longest_streak', 0)} days"
                    )
                else:
                    await message.channel.send(f"Error: {resp.get('error', 'Failed to fetch streak')}")
                return

        # Get all streaks
        resp, status = api_request("get", "/api/routines/streaks", token)
        if status == 200:
            streaks = resp if isinstance(resp, list) else []
            if not streaks:
                await message.channel.send("No streaks yet. Complete routines to build streaks! 🔥")
            else:
                lines = [f"- {s.get('routine_name')}: {s.get('current_streak')} day streak 🔥" for s in streaks]
                await message.channel.send("**Your Streaks:**\n" + "\n".join(lines))
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to fetch streaks')}")

    elif action == "templates":
        resp, status = api_request("get", "/api/templates", token)
        if status == 200:
            templates = resp if isinstance(resp, list) else []
            if not templates:
                await message.channel.send("No templates available yet.")
            else:
                lines = [f"- **{t['name']}**: {t.get('description', 'No description')}" for t in templates[:10]]
                await message.channel.send("**Available templates:**\n" + "\n".join(lines))
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to fetch templates')}")

    elif action == "clone":
        template_id = parsed.get("template_id")
        if not template_id:
            await message.channel.send("Which template would you like to clone?")
            return
        resp, status = api_request("post", f"/api/templates/{template_id}/clone", token)
        if status == 201:
            await message.channel.send(f"✅ Cloned! Created routine: **{resp.get('name')}**")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to clone template')}")

    elif action == "tag":
        routine_id = parsed.get("routine_id")
        tag_name = parsed.get("tag")
        if not routine_id or not tag_name:
            await message.channel.send("Please specify routine and tag.")
            return
        tags_resp, _ = api_request("get", "/api/tags", token)
        existing_tag = next((t for t in tags_resp if t.get("name", "").lower() == tag_name.lower()), None)
        if existing_tag:
            tag_id = existing_tag["id"]
        else:
            tag_resp, tag_status = api_request("post", "/api/tags", token, {"name": tag_name})
            if tag_status == 201:
                tag_id = tag_resp["id"]
            else:
                await message.channel.send(f"Error creating tag: {tag_resp.get('error')}")
                return
        resp, status = api_request("post", f"/api/routines/{routine_id}/tags", token, {"tag_ids": [tag_id]})
        if status == 200:
            await message.channel.send(f"🏷️ Added tag **{tag_name}** to routine!")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to add tag')}")

    elif action == "delete":
        routine_id = parsed.get("routine_id")
        name = parsed.get("name")
        needs_confirmation = parsed.get("needs_confirmation", True)
        
        routine_id, name, found = await _find_routine_by_name(message, token, routine_id, name)
        if not found:
            return
        
        if not routine_id:
            await message.channel.send("Which routine should I delete?")
            return
        
        # Handle confirmation
        if needs_confirmation:
            if "pending_confirmations" not in session:
                session["pending_confirmations"] = {}
            
            confirmation_id = f"routine_delete_{name}"
            session["pending_confirmations"][confirmation_id] = {
                "action": "delete",
                "interaction_type": "routine",
                "routine_id": routine_id,
                "name": name,
                "needs_confirmation": False  # Skip confirmation next time
            }
            
            await message.channel.send(
                f"⚠️ Are you sure you want to delete **{name}**?\n\n"
                f"This will also delete all steps and history for this routine.\n\n"
                f"Reply **yes** to confirm deletion, or **no** to cancel."
            )
            return
        
        # Actually delete
        resp, status = api_request("delete", f"/api/routines/{routine_id}", token)
        if status == 200:
            await message.channel.send(f"🗑️ Deleted **{name}** and all its data.")
        else:
            await message.channel.send(f"Error: {resp.get('error', 'Failed to delete routine')}")

    else:
        await message.channel.send(f"Unknown action: {action}. Try: list, create, delete, start, complete, skip, cancel, history, pause, resume, abort, note, stats, streak, templates, clone, or tag.")


async def _create_routine(message, token, name, description):
    """Helper to create a routine."""
    data = {"name": name, "description": description}
    resp, status = api_request("post", "/api/routines", token, data)
    if status == 201:
        await message.channel.send(f"✅ Created routine **{name}**!")
    else:
        await message.channel.send(f"Error: {resp.get('error', 'Failed to create routine')}")


async def _create_routine_with_steps(message, token, name, description, steps):
    """Helper to create a routine with steps."""
    # First create the routine
    data = {"name": name, "description": description}
    resp, status = api_request("post", "/api/routines", token, data)
    
    if status != 201:
        await message.channel.send(f"Error: {resp.get('error', 'Failed to create routine')}")
        return
    
    routine_id = resp.get("id")
    
    # Add each step
    success_count = 0
    for i, step_name in enumerate(steps):
        step_data = {
            "name": step_name,
            "duration_minutes": None  # API expects minutes, not seconds
        }
        step_resp, step_status = api_request("post", f"/api/routines/{routine_id}/steps", token, step_data)
        if step_status == 201:
            success_count += 1
    
    await message.channel.send(f"✅ Created **{name}** with {success_count} step(s)!")


async def _find_routine_by_name(message, token, routine_id, name):
    """Helper to find routine by name if ID not provided. Returns (routine_id, name, found)."""
    if routine_id:
        return routine_id, name, True
    
    if not name:
        return None, None, True  # Will prompt user later
    
    # Look up routine by name
    resp, status = api_request("get", "/api/routines", token)
    if status != 200:
        await message.channel.send("Error looking up routine. Please try again.")
        return None, None, False
    
    routines = resp if isinstance(resp, list) else []
    
    # Try exact match first
    matching = [r for r in routines if r['name'].lower() == name.lower()]
    
    # Then try partial match
    if not matching:
        matching = [r for r in routines if name.lower() in r['name'].lower() or r['name'].lower() in name.lower()]
    
    if not matching:
        await message.channel.send(f"❌ I couldn't find a routine called '{name}'.\n\nYour routines:\n" + 
            "\n".join([f"- {r['name']}" for r in routines[:10]]))
        return None, None, False
    
    if len(matching) > 1:
        # Multiple matches - show list
        lines = [f"{i+1}. {r['name']}" for i, r in enumerate(matching[:5])]
        await message.channel.send(
            f"🔍 I found multiple routines matching '{name}':\n" + 
            "\n".join(lines) + 
            "\n\nPlease specify which one (e.g., 'start 1' or say the full name)."
        )
        return None, None, False
    
    return matching[0]['id'], matching[0]['name'], True


def api_request(method, endpoint, token, data=None):
    import requests
    import os
    API_URL = os.getenv("API_URL", "http://app:5000")
    url = f"{API_URL}{endpoint}"
    headers = {"Content-Type": "application/json", "Authorization": f"Bearer {token}"}
    try:
        resp = getattr(requests, method)(url, headers=headers, json=data, timeout=10)
        try:
            return resp.json(), resp.status_code
        except ValueError:
            return {}, resp.status_code
    except requests.RequestException:
        return {"error": "API unavailable"}, 503


def validate_routine_json(data):
    errors = []
    if not isinstance(data, dict):
        return ["Response must be a JSON object"]
    if "error" in data:
        return []
    if "action" not in data:
        errors.append("Missing required field: action")
    return errors


register_module("routine", handle_routine)
ai_parser.register_validator("routine", validate_routine_json)
