import asyncio
import json
from fastapi import APIRouter, Depends, Query
from auth.dependencies import get_current_user
from auth.models import TokenPayload
from devices import service as devices_service
from users import service as users_service
from crm import service as crm_service
from melodies import service as melodies_service

router = APIRouter(prefix="/api/search", tags=["search"])

LIMIT = 5


def _truncate(s: str, n: int = 48) -> str:
    if not s:
        return ""
    return s if len(s) <= n else s[:n - 1] + "…"


def _search_devices(q: str) -> list[dict]:
    try:
        results = devices_service.list_devices(search=q)
    except Exception:
        return []
    out = []
    for d in results[:LIMIT]:
        label = d.device_name or d.serial_number or d.device_id or d.id
        sublabel = d.serial_number if d.device_name else None
        out.append({
            "type": "device",
            "id": d.id,
            "label": _truncate(label),
            "sublabel": _truncate(sublabel) if sublabel else None,
            "url": f"/devices/{d.id}",
        })
    return out


def _search_users(q: str) -> list[dict]:
    try:
        results = users_service.list_users(search=q)
    except Exception:
        return []
    out = []
    for u in results[:LIMIT]:
        label = u.display_name or u.email or u.id
        sublabel = u.email if u.display_name else None
        out.append({
            "type": "user",
            "id": u.id,
            "label": _truncate(label),
            "sublabel": _truncate(sublabel) if sublabel else None,
            "url": f"/users/{u.id}",
        })
    return out


def _search_customers(q: str) -> list[dict]:
    try:
        results = crm_service.list_customers(search=q)
    except Exception:
        return []
    out = []
    for c in results[:LIMIT]:
        name_parts = [c.name, c.surname]
        label = " ".join(p for p in name_parts if p) or c.organization or c.id
        sublabel_parts = []
        if c.organization and (c.name or c.surname):
            sublabel_parts.append(c.organization)
        if c.location:
            if c.location.city:
                sublabel_parts.append(c.location.city)
            if c.location.country:
                sublabel_parts.append(c.location.country)
        out.append({
            "type": "customer",
            "id": c.id,
            "label": _truncate(label),
            "sublabel": _truncate(" · ".join(sublabel_parts)) if sublabel_parts else None,
            "url": f"/crm/customers/{c.id}",
        })
    return out


def _search_products(q: str) -> list[dict]:
    try:
        results = crm_service.list_products(search=q)
    except Exception:
        return []
    out = []
    for p in results[:LIMIT]:
        sublabel_parts = []
        if p.category:
            sublabel_parts.append(p.category.value.replace("_", " ").title())
        if p.sku:
            sublabel_parts.append(p.sku)
        out.append({
            "type": "product",
            "id": p.id,
            "label": _truncate(p.name or p.id),
            "sublabel": _truncate(" · ".join(sublabel_parts)) if sublabel_parts else None,
            "url": f"/crm/products/{p.id}",
        })
    return out


async def _search_melodies(q: str) -> list[dict]:
    try:
        results = await melodies_service.list_melodies(search=q)
    except Exception:
        return []
    out = []
    for m in results[:LIMIT]:
        try:
            name_dict = json.loads(m.information.name) if m.information.name else {}
            label = name_dict.get("en") or name_dict.get("gr") or next(iter(name_dict.values()), None) or m.id
        except Exception:
            label = m.information.name or m.id
        sublabel_parts = []
        if m.pid:
            sublabel_parts.append(m.pid)
        if m.information.melodyTone:
            sublabel_parts.append(m.information.melodyTone.value.title())
        if m.information.totalActiveBells:
            sublabel_parts.append(f"{m.information.totalActiveBells} bells")
        out.append({
            "type": "melody",
            "id": m.id,
            "label": _truncate(label),
            "sublabel": _truncate(" · ".join(sublabel_parts)) if sublabel_parts else None,
            "url": f"/melodies/{m.id}",
        })
    return out


@router.get("")
async def global_search(
    q: str = Query(..., min_length=1, max_length=100),
    _user: TokenPayload = Depends(get_current_user),
):
    q = q.strip()
    if not q:
        return {"results": []}

    # Run sync searches in a thread pool, melody search is already async
    loop = asyncio.get_event_loop()
    devices_fut = loop.run_in_executor(None, _search_devices, q)
    users_fut = loop.run_in_executor(None, _search_users, q)
    customers_fut = loop.run_in_executor(None, _search_customers, q)
    products_fut = loop.run_in_executor(None, _search_products, q)
    melodies_task = _search_melodies(q)

    devices, users, customers, products, melodies = await asyncio.gather(
        devices_fut, users_fut, customers_fut, products_fut, melodies_task
    )

    results = []
    for group in (devices, users, customers, products, melodies):
        results.extend(group)

    return {"results": results}
