"""
Platform Gateway — Command bar handler (natural language actions via AI).
"""

import json
import urllib.request
from datetime import datetime

from config import OPENAI_API_KEY, OPENAI_MODEL, TRIPS_URL
from sessions import get_service_token
import proxy as _proxy_module
from proxy import proxy_request


def handle_command(handler, user, body):
    """Parse natural language command and execute it against the right service."""
    try:
        data = json.loads(body)
    except Exception as e:
        handler._send_json({"error": "Invalid JSON"}, 400)
        return

    command = data.get("command", "").strip()
    if not command:
        handler._send_json({"error": "No command provided"}, 400)
        return

    if not OPENAI_API_KEY:
        handler._send_json({"error": "AI not configured"}, 500)
        return

    # Get context: user's trips list and today's date
    trips_token = get_service_token(user["id"], "trips")

    trips_context = ""
    if trips_token:
        s, _, b = proxy_request(f"{TRIPS_URL}/api/trips", "GET",
                                {"Authorization": f"Bearer {trips_token['auth_token']}"}, timeout=5)
        if s == 200:
            trips_list = json.loads(b).get("trips", [])
            trips_context = "Available trips: " + ", ".join(
                f'"{t["name"]}" (id={t["id"]}, {t.get("start_date","")} to {t.get("end_date","")})' for t in trips_list
            )

    today = datetime.now().strftime("%Y-%m-%d")

    system_prompt = f"""You are a command executor for a personal platform with two services: Trips and Fitness.

Today's date: {today}
Current user: {user["display_name"]} (id={user["id"]})
{trips_context}

Parse the user's natural language command and return a JSON action to execute.

Return ONLY valid JSON with this structure:
{{
    "service": "trips" | "fitness",
    "action": "description of what was done",
    "api_call": {{
        "method": "POST" | "GET",
        "path": "/api/...",
        "body": {{ ... }}
    }}
}}

AVAILABLE ACTIONS:

For Trips service:
- Add location/activity: POST /api/location with {{"trip_id": "...", "name": "...", "category": "attraction|restaurant|cafe|hike|shopping", "visit_date": "YYYY-MM-DD", "start_time": "YYYY-MM-DDTHH:MM:SS", "description": "..."}}
- Add lodging: POST /api/lodging with {{"trip_id": "...", "name": "...", "type": "hotel", "check_in": "YYYY-MM-DDTHH:MM:SS", "check_out": "YYYY-MM-DDTHH:MM:SS", "location": "..."}}
- Add transportation: POST /api/transportation with {{"trip_id": "...", "name": "...", "type": "plane|car|train", "from_location": "...", "to_location": "...", "date": "YYYY-MM-DDTHH:MM:SS", "flight_number": "..."}}
- Add note: POST /api/note with {{"trip_id": "...", "name": "...", "content": "...", "date": "YYYY-MM-DD"}}
- Create trip: POST /api/trip with {{"name": "...", "start_date": "YYYY-MM-DD", "end_date": "YYYY-MM-DD", "description": "..."}}

For Fitness service:
- Log food (quick add): POST /api/entries with {{"entry_type": "quick_add", "meal_type": "breakfast|lunch|dinner|snack", "snapshot_food_name": "...", "snapshot_quantity": number, "snapshot_calories": number, "snapshot_protein": number, "snapshot_carbs": number, "snapshot_fat": number, "date": "YYYY-MM-DD"}}
  IMPORTANT for snapshot_food_name: use just the FOOD NAME without the quantity (e.g. "mini cinnabon" not "1/2 mini cinnabon"). Put the numeric quantity in snapshot_quantity (e.g. 0.5 for "half", 0.75 for "3/4").
- Search food first then log: If you know exact nutrition, use quick_add. Common foods: banana (105cal, 1g protein, 27g carbs, 0g fat), apple (95cal), egg (78cal, 6g protein, 1g carbs, 5g fat), chicken breast (165cal, 31g protein, 0g carbs, 3.6g fat), rice 1 cup (206cal, 4g protein, 45g carbs, 0g fat), bread slice (79cal, 3g protein, 15g carbs, 1g fat), milk 1 cup (149cal, 8g protein, 12g carbs, 8g fat), coffee black (2cal), oatmeal 1 cup (154cal, 5g protein, 27g carbs, 3g fat).

For Inventory service (searches NocoDB):
- Search items: GET /search-records?q=... (note: NO /api prefix for inventory)
- If user asks to search inventory, find items, look up orders, check serial numbers -- use service "inventory" with GET method

Guidelines:
- For food logging, default meal_type to "snack" if not specified
- For food logging, use today's date if not specified
- For trips, match the trip name fuzzy (e.g. "colorado" matches "Colorado")
- Use the trip_id from the available trips list
- Default check-in to 3PM, check-out to 11AM for hotels
- Estimate reasonable nutrition values for foods you know
- For inventory searches, use service "inventory" with method GET and path /search-records?q=searchterm
- IMPORTANT: Inventory paths do NOT start with /api/ -- use bare paths like /search-records"""

    # Call OpenAI
    try:
        ai_body = json.dumps({
            "model": OPENAI_MODEL,
            "messages": [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": command}
            ],
            "max_completion_tokens": 1000,
            "temperature": 0.1
        }).encode()

        req = urllib.request.Request(
            "https://api.openai.com/v1/chat/completions",
            data=ai_body,
            headers={
                "Content-Type": "application/json",
                "Authorization": f"Bearer {OPENAI_API_KEY}"
            },
            method="POST"
        )

        with urllib.request.urlopen(req, timeout=30) as resp:
            ai_result = json.loads(resp.read().decode())
            ai_text = ai_result["choices"][0]["message"]["content"]

        # Parse AI response
        ai_text = ai_text.strip()
        if ai_text.startswith("```json"):
            ai_text = ai_text[7:]
        if ai_text.startswith("```"):
            ai_text = ai_text[3:]
        if ai_text.endswith("```"):
            ai_text = ai_text[:-3]

        parsed = json.loads(ai_text.strip())

    except Exception as e:
        handler._send_json({"error": f"AI parsing failed: {e}"}, 500)
        return

    # Execute the action
    service = parsed.get("service", "")
    api_call = parsed.get("api_call", {})
    action_desc = parsed.get("action", "Unknown action")

    if not api_call or not api_call.get("path"):
        handler._send_json({"error": "AI could not determine action", "parsed": parsed}, 400)
        return

    # Get service token
    svc_token = get_service_token(user["id"], service)
    if not svc_token and service not in ("inventory",):
        handler._send_json({"error": f"{service} service not connected"}, 400)
        return

    # Build request to service
    target = _proxy_module.SERVICE_MAP.get(service)
    if not target:
        handler._send_json({"error": f"Unknown service: {service}"}, 400)
        return

    method = api_call.get("method", "POST")
    path = api_call.get("path", "")
    body_data = api_call.get("body", {})

    headers = {"Content-Type": "application/json"}
    if svc_token:
        headers["Authorization"] = f"Bearer {svc_token['auth_token']}"

    # For fitness food logging, use the resolve workflow instead of quick_add
    if service == "fitness" and body_data.get("entry_type") == "quick_add":
        food_name = body_data.get("snapshot_food_name", "")
        meal_type = body_data.get("meal_type", "snack")
        entry_date = body_data.get("date", datetime.now().strftime("%Y-%m-%d"))
        # AI-parsed quantity from the command (more reliable than resolve engine's parser)
        ai_quantity = body_data.get("snapshot_quantity")

        if food_name and svc_token:
            try:
                # Step 1: Resolve the food through the smart resolution engine
                resolve_body = json.dumps({
                    "raw_phrase": food_name,
                    "meal_type": meal_type,
                    "entry_date": entry_date,
                    "source": "command_bar"
                }).encode()
                rs, _, rb = proxy_request(
                    f"{target}/api/foods/resolve", "POST",
                    {**headers, "Content-Type": "application/json"}, resolve_body, timeout=15
                )

                if rs == 200:
                    resolved = json.loads(rb)
                    res_type = resolved.get("resolution_type")
                    matched = resolved.get("matched_food")
                    parsed_food = resolved.get("parsed", {})

                    if matched and res_type in ("matched", "ai_estimated", "confirm"):
                        food_id = matched.get("id")
                        # For new foods (ai_estimated): serving was created for the exact request
                        # e.g. "3/4 cup biryani" -> serving = "3/4 cup" at 300 cal -> qty = 1.0
                        # For existing foods (matched/confirm): use AI quantity as multiplier
                        # e.g. "half cinnabon" -> existing "1 mini cinnabon" at 350 cal -> qty = 0.5
                        if res_type == "ai_estimated":
                            quantity = 1.0
                        elif ai_quantity and ai_quantity != 1:
                            quantity = ai_quantity
                        else:
                            quantity = 1.0

                        body_data = {
                            "food_id": food_id,
                            "meal_type": meal_type,
                            "quantity": quantity,
                            "date": entry_date,
                            "entry_type": "food"
                        }

                        # Use matching serving if available
                        servings = matched.get("servings", [])
                        if servings:
                            body_data["serving_id"] = servings[0].get("id")

                        # Use snapshot name override if provided (includes modifiers)
                        if resolved.get("snapshot_name_override"):
                            body_data["snapshot_food_name_override"] = resolved["snapshot_name_override"]
                        if resolved.get("note"):
                            body_data["note"] = resolved["note"]

                        action_desc = f"Logged {matched.get('name', food_name)} for {meal_type}"
                        if res_type == "ai_estimated":
                            action_desc += " (AI estimated, added to food database)"

                        # Auto-fetch image if food doesn't have one
                        if not matched.get("image_path") and food_id:
                            try:
                                img_body = json.dumps({"query": matched.get("name", food_name) + " food"}).encode()
                                si, _, sb = proxy_request(
                                    f"{target}/api/images/search", "POST",
                                    {**headers, "Content-Type": "application/json"}, img_body, timeout=8
                                )
                                if si == 200:
                                    imgs = json.loads(sb).get("images", [])
                                    if imgs:
                                        img_url = imgs[0].get("url") or imgs[0].get("thumbnail")
                                        if img_url:
                                            proxy_request(
                                                f"{target}/api/foods/{food_id}/image", "POST",
                                                {**headers, "Content-Type": "application/json"},
                                                json.dumps({"url": img_url}).encode(), timeout=10
                                            )
                            except Exception as e:
                                print(f"[Command] Auto-image fetch failed: {e}")

            except Exception as e:
                print(f"[Command] Food resolve failed, falling back to quick_add: {e}")

    req_body = json.dumps(body_data).encode() if body_data else None

    status, resp_headers, resp_body = proxy_request(f"{target}{path}", method, headers, req_body, timeout=15)

    try:
        result = json.loads(resp_body)
    except Exception as e:
        result = {"raw": resp_body.decode()[:200]}

    handler._send_json({
        "success": status < 400,
        "action": action_desc,
        "service": service,
        "status": status,
        "result": result
    })
