"""Van inventory command — parse receipts and item lists via LLM, push to API."""

from __future__ import annotations

import json
import logging
from typing import TYPE_CHECKING, Any

import httpx

from python.signal_bot.models import InventoryItem, InventoryUpdate

if TYPE_CHECKING:
    from python.signal_bot.llm_client import LLMClient
    from python.signal_bot.models import SignalMessage
    from python.signal_bot.signal_client import SignalClient

logger = logging.getLogger(__name__)

SYSTEM_PROMPT = """\
You are an inventory assistant. Extract items from the input and return ONLY
a JSON array. Each element must have these fields:
  - "name": item name (string)
  - "quantity": numeric count or amount (default 1)
  - "unit": unit of measure (e.g. "each", "lb", "oz", "gallon", "bag", "box")
  - "category": category like "food", "tools", "supplies", etc.
  - "notes": any extra detail (empty string if none)

Example output:
[{"name": "water bottles", "quantity": 6, "unit": "gallon", "category": "supplies", "notes": "1 gallon each"}]

Return ONLY the JSON array, no other text.\
"""

IMAGE_PROMPT = "Extract all items from this receipt or inventory photo."
TEXT_PROMPT = "Extract all items from this inventory list."


def parse_llm_response(raw: str) -> list[InventoryItem]:
    """Parse the LLM JSON response into InventoryItem list."""
    text = raw.strip()
    # Strip markdown code fences if present
    if text.startswith("```"):
        lines = text.split("\n")
        lines = [line for line in lines if not line.startswith("```")]
        text = "\n".join(lines)

    items_data: list[dict[str, Any]] = json.loads(text)
    return [InventoryItem.model_validate(item) for item in items_data]


def _upsert_item(api_url: str, item: InventoryItem) -> None:
    """Create or update an item via the van_inventory API.

    Fetches existing items, and if one with the same name exists,
    patches its quantity (summing). Otherwise creates a new item.
    """
    base = api_url.rstrip("/")
    response = httpx.get(f"{base}/api/items", timeout=10)
    response.raise_for_status()
    existing: list[dict[str, Any]] = response.json()

    match = next((e for e in existing if e["name"].lower() == item.name.lower()), None)

    if match:
        new_qty = match["quantity"] + item.quantity
        patch = {"quantity": new_qty}
        if item.category:
            patch["category"] = item.category
        response = httpx.patch(f"{base}/api/items/{match['id']}", json=patch, timeout=10)
        response.raise_for_status()
        return
    payload = {
        "name": item.name,
        "quantity": item.quantity,
        "unit": item.unit,
        "category": item.category or None,
    }
    response = httpx.post(f"{base}/api/items", json=payload, timeout=10)
    response.raise_for_status()


def handle_inventory_update(
    message: SignalMessage,
    signal: SignalClient,
    llm: LLMClient,
    api_url: str,
) -> InventoryUpdate:
    """Process an inventory update from a Signal message.

    Accepts either an image (receipt photo) or text list.
    Uses the LLM to extract structured items, then pushes to the van_inventory API.
    """
    try:
        logger.info(f"Processing inventory update from {message.source}")
        if message.attachments:
            image_data = signal.get_attachment(message.attachments[0])
            raw_response = llm.chat(
                IMAGE_PROMPT,
                image_data=image_data,
                system=SYSTEM_PROMPT,
            )
            source_type = "receipt_photo"
        elif message.message.strip():
            raw_response = llm.chat(
                f"{TEXT_PROMPT}\n\n{message.message}",
                system=SYSTEM_PROMPT,
            )
            source_type = "text_list"
        else:
            signal.reply(message, "Send a photo of a receipt or a text list of items to update inventory.")
            return InventoryUpdate()

        logger.info(f"{raw_response=}")

        new_items = parse_llm_response(raw_response)

        logger.info(f"{new_items=}")

        for item in new_items:
            _upsert_item(api_url, item)

        summary = _format_summary(new_items)
        signal.reply(message, f"Inventory updated with {len(new_items)} item(s):\n{summary}")

        return InventoryUpdate(items=new_items, raw_response=raw_response, source_type=source_type)

    except Exception:
        logger.exception("Failed to process inventory update")
        signal.reply(message, "Failed to process inventory update. Check logs for details.")
        return InventoryUpdate()


def _format_summary(items: list[InventoryItem]) -> str:
    """Format items into a readable summary."""
    lines = [f"  - {item.name} x{item.quantity} {item.unit} [{item.category}]" for item in items]
    return "\n".join(lines)
